add a package for a interface(or not executable) library
Life4gal opened this issue · comments
I noticed the CMakeList.txt file at the top level of your project, the line 55
# Link dependencies
target_link_libraries(Greeter PRIVATE fmt::fmt)
Use target_link_libraries to link an external library which add by
CPMAddPackage(
NAME fmt
GIT_TAG 7.1.3
GITHUB_REPOSITORY fmtlib/fmt
OPTIONS "FMT_INSTALL YES" # create an installable target
)
I am puzzled why this can be done, as far as I know, this will remind me of an error on my IDE (CLion).
Cannot specify link libraries for target "PROJECT_NAME" which is not built by this project.
This is the structure of my project:
cmake
|--- CPM.cmakeexec
|--- main.cpp
|--- CMakeList.txtinclude
|--- *.hppsrc
|--- *.cppCMakeList.txt
The content of CMakeList.txt in top level:
cmake_minimum_required(VERSION 2.8.12...3.17)
project(
foo
VERSION 0.0.1
LANGUAGES CXX
)
include(cmake/CPM.cmake)
CPMAddPackage("gh:TheLartians/PackageProject.cmake#master")
file(GLOB_RECURSE fooHeader CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp")
file(GLOB_RECURSE fooSource CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(
${PROJECT_NAME}
${fooHeader}
${fooSource}
)
set_target_properties(
${PROJECT_NAME} PROPERTIES
LINKER_LANGUAGE CXX
CXX_STANDARD 17
)
# being a cross-platform target, we enforce standards conformance on MSVC
target_compile_options(${PROJECT_NAME} PUBLIC "$<$<BOOL:${MSVC}>:/permissive->")
# MARK1
# CPMAddPackage("gh:jarro2783/cxxopts#master")
# set(CXXOPTS_BUILD_EXAMPLES off)
# set(CXXOPTS_BUILD_TESTS off)
# target_link_libraries(${PROJECT_NAME} cxxopts)
target_include_directories(
${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include/${PROJECT_NAME}-${PROJECT_VERSION}>
)
string(TOLOWER ${PROJECT_NAME}/version.h VERSION_HEADER_LOCATION)
packageProject(
NAME ${PROJECT_NAME}
VERSION ${PROJECT_VERSION}
NAMESPACE ${PROJECT_NAME}
BINARY_DIR ${PROJECT_BINARY_DIR}
INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include
INCLUDE_DESTINATION include/${PROJECT_NAME}-${PROJECT_VERSION}
VERSION_HEADER "${VERSION_HEADER_LOCATION}"
DEPENDENCIES "foo"
)
The content of CMakeList.txt in exec:
cmake_minimum_required(VERSION 2.8.12...3.17)
project(
fooExec
LANGUAGES CXX
)
include(../cmake/CPM.cmake)
CPMAddPackage(
NAME foo
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/..
)
add_executable(
${PROJECT_NAME}
main.cpp
)
set_target_properties(
${PROJECT_NAME}
PROPERTIES CXX_STANDARD 17
OUTPUT_NAME "fooExec"
)
# MARK2
CPMAddPackage("gh:jarro2783/cxxopts#master")
set(CXXOPTS_BUILD_EXAMPLES off)
set(CXXOPTS_BUILD_TESTS off)
target_link_libraries(
${PROJECT_NAME}
PRIVATE
foo::foo
)
You may have noticed that I have a mark in each of the two files.
At the beginning, I wrote the code that needs cxxopts in the exec folder (the same directory as main.cpp) and the exec folder's structure is similar to the top level (also has include and src folders), I use
target_link_libraries(
${PROJECT_NAME}
PRIVATE
foo::foo
cxxopts
)
everything work well
// and if I write
#include <cxx
// It immediately reminds me whether to write
#include <cxxopts.hpp>
// Yes, IDE knows that there is a file called cxxopts.hpp
But soon I discovered that there are some problems with the design of this structure. I need to move the code that uses cxxopts to the include and src folders at the top level. So I tried to delete the cxxopts at MARK2 to
target_link_libraries(
${PROJECT_NAME}
PRIVATE
foo::foo
)
And added the code at MARK1 (they didn't exist at the beginning).
CPMAddPackage("gh:jarro2783/cxxopts#master")
set(CXXOPTS_BUILD_EXAMPLES off)
set(CXXOPTS_BUILD_TESTS off)
# the code below is also not exist now
# target_link_libraries(${PROJECT_NAME} cxxopts)
then
```c++
// and if I write
#include <cxx
// It reminds me nothing
#include <cxxopts.hpp>
// Yes, IDE does not knows that there is a file called cxxopts.hpp and it tells me file not found
After this, I came back here, I use target_link_libraries like you
CPMAddPackage("gh:jarro2783/cxxopts#master")
set(CXXOPTS_BUILD_EXAMPLES off)
set(CXXOPTS_BUILD_TESTS off)
target_link_libraries(${PROJECT_NAME} cxxopts)
What I didn’t expect was that the error this time was not
Cannot specify link libraries for target "PROJECT_NAME" which is not built by this project.
It output
CMake Error: install(EXPORT "fooTargets" ...) includes target "foo" which requires target "cxxopts" that is not in any export set.
What I didn't expect again is
// and if I write
#include <cxx
// It immediately reminds me whether to write
#include <cxxopts.hpp>
// Yes, IDE knows that there is a file called cxxopts.hpp again!!!
I don't know what to do.
- Be sure to define the option before adding the package as cache variables, or simply provide them to CPM.cmake in the
OPTIONS
parameter, as otherwise the package might ignore them. - I think the error is due to the fact that
cxxopts
isn't installable by default. You should also provide theCXXOPTS_ENABLE_INSTALL
parameter. We should probably add it in the starter as well. - Also prefer git tags as version identifiers, as otherwise the build won't be reproducible in the future.
CPMAddPackage(
GITHUB_REPOSITORY jarro2783/cxxopts
VERSION 2.2.1
OPTIONS
"CXXOPTS_BUILD_EXAMPLES OFF"
"CXXOPTS_BUILD_TESTS OFF"
"CXXOPTS_ENABLE_INSTALL ON"
)
- Be sure to define the option before adding the package as cache variables, or simply provide them to CPM.cmake in the
OPTIONS
parameter, as otherwise the package might ignore them.- I think the error is due to the fact that
cxxopts
isn't installable by default. You should also provide theCXXOPTS_ENABLE_INSTALL
parameter. We should probably add it in the starter as well.- Also prefer git tags as version identifiers, as otherwise the build won't be reproducible in the future.
CPMAddPackage( GITHUB_REPOSITORY jarro2783/cxxopts VERSION 2.2.1 OPTIONS "CXXOPTS_BUILD_EXAMPLES OFF" "CXXOPTS_BUILD_TESTS OFF" "CXXOPTS_ENABLE_INSTALL ON" )
Yes this eliminates the error, but can you explain to me why it doesn't work of my code?
What puzzles me most is why my code still runs normally despite the error reported by CMake.
You're adding cxxopts, which is not configured for installation, to a library that is. As you need to be able install all dependencies, CMake gives an error. By configuring cxxopts for installation this error is resolved.
You're adding cxxopts, which is not configured for installation, to a library that is. As you need to be able install all dependencies, CMake gives an error. By configuring cxxopts for installation this error is resolved.
Could you please tell me what should I do if I want to install nlohmann/json(or nlohmann/json's FetchContent)(and others library) in this way?
Because it seems that not all libraries have a "FOO_ENABLE_INSTALL YES" option, sorry, I don’t know much about this :)
The example not suitable for me, as mentioned earlier, my top level project is not built by itself.
Oh yeah, seems we missed that in the example. You'd have to set JSON_Install
to YES
in this case. Unfortunately, as far as I know, there is no great way of doing this besides looking at the project's CMakeLists and finding out how to enable the libraries installation from there.
Oh yeah, seems we missed that in the example. You'd have to set
JSON_Install
toYES
in this case. Unfortunately, as far as I know, there is no great way of doing this besides looking at the project's CMakeLists and finding out how to enable the libraries installation from there.
# fmt always work well :)
CPMAddPackage(
NAME fmt
GIT_TAG master
GITHUB_REPOSITORY fmtlib/fmt
# create an installable target, this is necessary
# https://github.com/fmtlib/fmt/blob/9cb347b4b2e80fc9fbf57b8621746663c3f870f6/CMakeLists.txt#L67
OPTIONS "FMT_INSTALL YES"
)
CPMAddPackage(
NAME nlohmann_json
VERSION 3.9.1
# the git repo is incredibly large, so we download the archived include directory
URL https://github.com/nlohmann/json/releases/download/v3.9.1/include.zip
URL_HASH SHA256=6bea5877b1541d353bd77bdfbdb2696333ae5ed8f9e8cc22df657192218cad91
# https://github.com/nlohmann/json/blob/823801879ab9a99440b300a02b737c11e806d207/CMakeLists.txt#L34
# why no effect
OPTIONS "JSON_Install YES"
)
# todo: If the following code exists, everything work well, but...
# CMake Error: install(EXPORT "StarterTemplateTargets" ...) includes target "StarterTemplate" which requires target "nlohmann_json" that is not in any export set.
if(nlohmann_json_ADDED)
add_library(nlohmann_json INTERFACE)
target_include_directories(nlohmann_json SYSTEM INTERFACE ${nlohmann_json_SOURCE_DIR}/include)
endif()
target_link_libraries(
${PROJECT_NAME}
PUBLIC
fmt
nlohmann_json
)
Oh yeah you're creating your own JSON target, that isn't installable. Try replacing the block
CPMAddPackage(
NAME nlohmann_json
VERSION 3.9.1
# the git repo is incredibly large, so we download the archived include directory
URL https://github.com/nlohmann/json/releases/download/v3.9.1/include.zip
URL_HASH SHA256=6bea5877b1541d353bd77bdfbdb2696333ae5ed8f9e8cc22df657192218cad91
# https://github.com/nlohmann/json/blob/823801879ab9a99440b300a02b737c11e806d207/CMakeLists.txt#L34
# why no effect
OPTIONS "JSON_Install YES"
)
# todo: If the following code exists, everything work well, but...
# CMake Error: install(EXPORT "StarterTemplateTargets" ...) includes target "StarterTemplate" which requires target "nlohmann_json" that is not in any export set.
if(nlohmann_json_ADDED)
add_library(nlohmann_json INTERFACE)
target_include_directories(nlohmann_json SYSTEM INTERFACE ${nlohmann_json_SOURCE_DIR}/include)
endif()
with something like
CPMAddPackage(
NAME nlohmann_json
VERSION 3.9.1
OPTIONS
"JSON_Install ON"
"JSON_BuildTests OFF"
)
Be sure to set the CPM_SOURCE_CACHE
environmental variable (e.g. to ~/.cache/cpm
) to allow a shallow clone and avoid redundant downloads of the repo.
Oh yeah you're creating your own JSON target, that isn't installable. Try replacing the block
CPMAddPackage( NAME nlohmann_json VERSION 3.9.1 # the git repo is incredibly large, so we download the archived include directory URL https://github.com/nlohmann/json/releases/download/v3.9.1/include.zip URL_HASH SHA256=6bea5877b1541d353bd77bdfbdb2696333ae5ed8f9e8cc22df657192218cad91 # https://github.com/nlohmann/json/blob/823801879ab9a99440b300a02b737c11e806d207/CMakeLists.txt#L34 # why no effect OPTIONS "JSON_Install YES" ) # todo: If the following code exists, everything work well, but... # CMake Error: install(EXPORT "StarterTemplateTargets" ...) includes target "StarterTemplate" which requires target "nlohmann_json" that is not in any export set. if(nlohmann_json_ADDED) add_library(nlohmann_json INTERFACE) target_include_directories(nlohmann_json SYSTEM INTERFACE ${nlohmann_json_SOURCE_DIR}/include) endif()with something like
CPMAddPackage( NAME nlohmann_json VERSION 3.9.1 OPTIONS "JSON_Install ON" "JSON_BuildTests OFF" )Be sure to set the
CPM_SOURCE_CACHE
environmental variable (e.g. to~/.cache/cpm
) to allow a shallow clone and avoid redundant downloads of the repo.
This can indeed solve the problem, but it will bring a problem that cannot be ignored: the size of the json library is 250MB.
My operating system is KDE (ubuntu20.04) and the IDE I use is CLion. Can you explain what you said [set the CPM_SOURCE_CACHE
], or how to do it, I don’t really understand.
If you add something like export CPM_SOURCE_CACHE=$HOME/.cache/CPM
to your .bash_profile
, CPM.cmake will cache downloads and also use shallow clones. In that case the json library still needs around 170mb, but it will be downloaded only once on your system. See the CPM.cmake docs for more info.
Alternatively, you can download only the header as before, but then it's your responsibility to create an installable target. Another option that could work would be to simply add the include to your main (already installable) target target_include_directories(${PROJECT_NAME} PRIVATE ${nlohmann_json_SOURCE_DIR}/include)
.