I am trying to automate the fetch a few dependencies in CMakeList.txt, using FetchContent_Declare and FetchContent_MakeAvailable.
However I found the following error when running cmake
CMake Error at build/_deps/hermes-src/cmake/modules/Hermes.cmake:123 (add_library):
add_library cannot create target "gtest" because another target with the
same name already exists. The existing target is a static library created
in source directory
"/path/to/build/_deps/googletest-src/googletest". See
documentation for policy CMP0002 for more details.
Call Stack (most recent call first):
build/_deps/hermes-src/external/llvh/utils/unittest/CMakeLists.txt:53 (add_hermes_library)
CMake Error at build/_deps/hermes-src/cmake/modules/Hermes.cmake:123 (add_library):
add_library cannot create target "gtest_main" because another target with
the same name already exists. The existing target is a static library
created in source directory
"path/to/build/_deps/googletest-src/googletest". See
documentation for policy CMP0002 for more details.
Call Stack (most recent call first):
build/_deps/hermes-src/external/llvh/utils/unittest/UnitTestMain/CMakeLists.txt:1 (add_hermes_library)
This is the CMakeLists.txt to reproduce
cmake_minimum_required(VERSION 3.13)
project(pytorch_live_cxx)
set(CMAKE_CXX_STANDARD 14)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
)
FetchContent_MakeAvailable(googletest)
FetchContent_Declare(
hermes
URL https://github.com/facebook/hermes/archive/d63feeb46d26fe0ca7e789fc793f409e5158b27f.zip
)
FetchContent_MakeAvailable(hermes)
My questions:
does that mean hermes has googletest as dependencies? If so, I can just call target_link_libraries(myexec, gtest) without calling fetching googletest?
Is there any better practice to avoid target name conflict like this? This is an example in my imagination: we have package A which builds target a and b, and package B which builds targets b and c. What should I do if I want to links to all a, b and c?
Thanks
Related
I have been trying to build, and correctly set up Cmake with SFML using find_package + SFMLConfig.cmake.
Cmake correctly finds a configuration file (along with ConfigDependencies, ConfigVersion, ConfigSharedTargets) at default linux install location per the SFML compilation instructions:
/usr/local/lib/cmake/sfml
However at that path there is no shared library files (.so).
all of them (audio, graphics, network, system and window) are all the way up at:
/usr/local/lib
So i believe i have correctly built and "installed" SFML with make.
I get this error message (for all four components):
CMake Error at /usr/local/lib/cmake/SFML/SFMLConfig.cmake:150 (message):
Found SFML but requested component 'audio' is missing in the config defined in /usr/local/lib/cmake/SFML.
Call Stack (most recent call first):
CMakeLists.txt:17 (find_package)
CMake Error at CMakeLists.txt:17 (find_package): Found package configuration file:
/usr/local/lib/cmake/SFML/SFMLConfig.cmake
but it set SFML_FOUND to FALSE so package "SFML" is considered to be NOT FOUND.
I have tried to set the SFML_DIR variable in my CMakeLists.txt to many different places, both where i store SFML source (where i git cloned), where i built in to SFML-build. and where it is installed.
Why are the components missing? Should i copy the .so files into where the SFMLConfig.cmake file is? Should i move the SFMLConfig.cmake and update CMAKE_MODULE_PATH to a new path?
Looking into the SFMLConfig.cmake i see that the last if and elseif Statements in the code below is the one that fails. Meaning
TARGET SFML::${component} evaluates false. But I'm not sure what that means.
#SFMLConfig.cmake
foreach(component ${SFML_FIND_COMPONENTS})
string(TOUPPER "${component}" UPPER_COMPONENT)
list(APPEND FIND_SFML_ADDITIONAL_COMPONENTS ${FIND_SFML_${UPPER_COMPONENT}_DEPENDENCIES})
endforeach()
list(APPEND SFML_FIND_COMPONENTS ${FIND_SFML_ADDITIONAL_COMPONENTS})
list(REMOVE_DUPLICATES SFML_FIND_COMPONENTS)
[...]
foreach (component ${SFML_FIND_COMPONENTS})
string(TOUPPER "${component}" UPPER_COMPONENT)
set(SFML_${UPPER_COMPONENT}_FOUND FALSE)
if (TARGET SFML::${component})
set(SFML_${UPPER_COMPONENT}_FOUND TRUE)
elseif(SFML_FIND_REQUIRED_${component})
set(FIND_SFML_ERROR "Found SFML but requested component '${component}' is missing in the config defined in ${SFML_DIR}.")
set(SFML_FOUND FALSE)
endif()
endforeach()
This is my top CMakeLists.txt file:
set(CMAKE_MODULE_PATH "/usr/local/lib/cmake/SFML") # tell cmake where to find find.cmake and config.cmake files
set(SFML_DIR "/usr/local/lib")
find_package(SFML COMPONENTS graphics window system audio REQUIRED) # Look for SFML
When I use CMake FetchContent to import OpenCV, it works fine:
include(FetchContent)
# Fetch OpenCV
FetchContent_Declare(
opencv
GIT_REPOSITORY https://gitee.com/aiproach/opencv.git
GIT_TAG 4.4.0
)
FetchContent_MakeAvailable(opencv)
set(OpenCV_DIR ${CMAKE_CURRENT_BINARY_DIR})
find_package(OpenCV REQUIRED)
But after I add Eigen:
# Fetch Eigen
FetchContent_Declare(
eigen
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
GIT_TAG 3.3.9
)
FetchContent_MakeAvailable(eigen)
find_package(eigen3 REQUIRED)
It emits errors:
CMake Error at build/_deps/eigen-src/CMakeLists.txt:620 (add_custom_target):
add_custom_target cannot create target "uninstall" because another target
with the same name already exists. The existing target is a custom target
created in source directory
"...../build/_deps/opencv-src".
See documentation for policy CMP0002 for more details.
CMake Error at build/_deps/eigen-build/eigen3Config.cmake:20 (include):
The file
....../build/_deps/eigen-build/Eigen3Targets.cmake
was generated by the export() command. It may not be used as the argument
to the include() command. Use ALIAS targets instead to refer to targets by
alternative names.
Call Stack (most recent call first):
CMakeLists.txt:30 (find_package)
I was told that this is caused by namespace collision, but I don't know how to solve that issue. I searched for "FetchContent" on GitHub, but it seems everybody is using it the same way as mine. Is there a general way to fetch everything using FetchContent with just the effort to insert the project name and URL?
When the clashes are between targets from different project dependencies, there's not much you can do right now except politely ask the project maintainers to consider modifying their non-import/export target names to be namespaced like.
You could try to work around the problem by patching their CMake files after the download. If you're using the ExternalProject module or the FetchContent module (which is built on top of ExternalProject), you might be able to do this with the PATCH_COMMAND argument (see the docs), which "Specifies a custom command to patch the sources after an update.". But I've never tried this myself and it sounds like a pain to do.
For example, for a library target, that might look like:
add_library(projectname_targetnamepart)
add_library("importexportnamespacename::targetnamepart" ALIAS projectname_targetnamepart)
set_target_properties(projectname_targetnamepart PROPERTIES EXPORT_NAME targetnamepart)
set_target_properties(projectname_targetnamepart PROPERTIES OUTPUT_NAME targetnamepart)
install(TARGETS projectname_targetnamepart EXPORT projectname_targets ...)
install(EXPORT projectname_targets NAMESPACE "importexportnamespacename::" ...)
There's a Kitware issue ticket by Craig Scott proposing a CMake feature for Project-level namespaces. Here's an excerpt:
A common problem when pulling in subprojects using add_subdirectory() is that target names must be unique, but different subprojects might try to use the same target name, which results in a name clash. This issue proposes to introduce the concept of a project namespace to address this and related name uniqueness problems (this is the primary goal of this issue).
Sometimes the upstream maintainer will just decline to support the add_subdirectory / FetchContent use-case. That's the case with OpenCV, as shown in this issue ticket (#16896). As for eigen, there's an open ticket that hasn't had any activity in a while (#1892).
Someone else had a similar question here: Isolating gitsubmodule projects in CMake, and indicated in the comments that they were able to resolve their issues by using the Hunter package manager, so perhaps you could give that a try.
I have the latest assimp source code (5.0.1 release), I have built it with CMake and installed using cmake --install. Now I am trying to add it to my CMake project: find_package(Assimp REQUIRED Assimp) - at this moment it configures fine. The problems started when I tried to add
target_link_libraries(
MyProj PRIVATE
Assimp::Assimp
)
And I get the following error:
[cmake] target "MyProj" links to target "Assimp::Assimp" but the target
[cmake] was not found. Perhaps a find_package() call is missing for an IMPORTED
[cmake] target, or an ALIAS target is missing?
After some research, I've tried target_link_libraries(MyProj PRIVATE ${ASSIMP_LIBRARIES}), this time I got a compile error, and when I displayed the value of the ${ASSIMP_LIBRARIES} variable (command: message("${ASSIMP_LIBRARIES}")) I got: assimp-vc142-mt.dll - it contains .dll name, even without full path. Have a lot of troubles with assimp, could anyone suggest a solution?
Without having any knowledge of assimp, I think what you want is this:
target_link_libraries(MyProj PRIVATE assimp::assimp)
As far as I know, CMake target names are case sensitive and the assimp::assimp alias target is created here with lowercase a.
I'm running into a CMake issue that I am a little stumped by. It involves a CMake project that builds dependencies for an application I develop at work. I now have to add a new dependency, libnest2d, which itself also has three dependencies, of which some are also new.
To get libnest2d to build I have this ExternalProject_Add call:
ExternalProject_Add(libnest2d
GIT_REPOSITORY https://github.com/tamasmeszaros/libnest2d.git
GIT_TAG da4782500da4eb8cb6e38e5e3f10164ec5a59778
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_PREFIX_PATH=${CMAKE_INSTALL_PREFIX}
-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
DEPENDS BoostHeaders nlopt Clipper
)
This project depends on the Boost Headers, NLopt and Clipper. Those Boost headers and Clipper are fine, but it somehow complains about NLopt with the following errors:
CMake Error at /usr/share/cmake-3.16/Modules/ExternalProject.cmake:2962 (get_property):
get_property could not find TARGET nlopt. Perhaps it has not yet been
created.
Call Stack (most recent call first):
/usr/share/cmake-3.16/Modules/ExternalProject.cmake:3239 (_ep_add_configure_command)
projects/libnest2d.cmake:5 (ExternalProject_Add)
CMakeLists.txt:61 (include)
CMake Error at /usr/share/cmake-3.16/Modules/ExternalProject.cmake:2964 (get_property):
get_property could not find TARGET nlopt. Perhaps it has not yet been
created.
Call Stack (most recent call first):
/usr/share/cmake-3.16/Modules/ExternalProject.cmake:3239 (_ep_add_configure_command)
projects/libnest2d.cmake:5 (ExternalProject_Add)
CMakeLists.txt:61 (include)
CMake Error at /usr/share/cmake-3.16/Modules/ExternalProject.cmake:1783 (get_property):
get_property could not find TARGET nlopt. Perhaps it has not yet been
created.
Call Stack (most recent call first):
/usr/share/cmake-3.16/Modules/ExternalProject.cmake:2064 (ExternalProject_Get_Property)
/usr/share/cmake-3.16/Modules/ExternalProject.cmake:2966 (_ep_get_step_stampfile)
/usr/share/cmake-3.16/Modules/ExternalProject.cmake:3239 (_ep_add_configure_command)
projects/libnest2d.cmake:5 (ExternalProject_Add)
CMakeLists.txt:61 (include)
CMake Error at /usr/share/cmake-3.16/Modules/ExternalProject.cmake:1785 (message):
External project "nlopt" has no stamp_dir
Call Stack (most recent call first):
/usr/share/cmake-3.16/Modules/ExternalProject.cmake:2064 (ExternalProject_Get_Property)
/usr/share/cmake-3.16/Modules/ExternalProject.cmake:2966 (_ep_get_step_stampfile)
/usr/share/cmake-3.16/Modules/ExternalProject.cmake:3239 (_ep_add_configure_command)
projects/libnest2d.cmake:5 (ExternalProject_Add)
CMakeLists.txt:61 (include)
So it states that the nlopt target is not defined. However that target is defined using another ExternalProject_Add call, the same as the other two dependencies:
ExternalProject_Add(nlopt
GIT_REPOSITORY https://github.com/stevengj/nlopt.git
GIT_TAG v2.6.2
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_PREFIX_PATH=${CMAKE_INSTALL_PREFIX}
-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
)
ExternalProject_Add(BoostHeaders
URL http://sourceforge.net/projects/boost/files/boost/1.67.0/boost_1_67_0.tar.bz2
URL_HASH SHA1=694ae3f4f899d1a80eb7a3b31b33be73c423c1ae
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_BINARY_DIR}/BoostHeaders-prefix/src/BoostHeaders/boost" "${CMAKE_INSTALL_PREFIX}/include/boost"
)
ExternalProject_Add(Clipper
URL https://sourceforge.net/projects/polyclipping/files/clipper_ver6.4.2.zip
URL_HASH SHA1=b05c1f454c22576f867fc633b11337d053e9ea33
SOURCE_SUBDIR cpp
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_PREFIX_PATH=${CMAKE_INSTALL_PREFIX}
-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
)
Without the NLopt dependency, libnest2d builds fine (since I still have the dependency installed on my local system), but there is no guarantee that NLopt is built and installed before starting on libnest2d, and indeed this goes wrong if I execute this build in a VM with multiple threads.
If I temporarily remove the nlopt dependency and call cmake .. && make help then I see that nlopt is one of the available targets. I can also call make nlopt and it starts building NLopt as expected.
You can view my entire source code here: https://github.com/Ultimaker/cura-build-environment/tree/CURA-7259_pynest2d . As of this writing I'm on commit 39298d203d115b60d7093f0a801be1bad0ba7842.
Other problems I've found have not been the same and don't provide a solution for me:
This related question has the same error but it seems to be caused by a tool that OP was using, which I'm not using.
This question and this bug report were a problem with a target that was disabled by a build option, which is not the case for me. The target clearly exists and I made no option to disable it.
There was an old bug that caused this but it was fixed in CMake 2.8. I'm using CMake 3.16.3.
So to summarize, how can I cause the libnest2d external project to depend on NLopt? Why are two dependencies accepted, but one isn't?
I went over the grpc installation and finished building and installation.
Now when I try to:
find_package(gRPC CONFIG REQUIRED)
I get
CMake Error at CMakeLists.txt:15 (find_package):
Found package configuration file:
/usr/lib64/cmake/grpc/gRPCConfig.cmake
but it set gRPC_FOUND to FALSE so package "gRPC" is considered to be NOT
FOUND. Reason given by package:
The following imported targets are referenced, but are missing:
protobuf::libprotobuf protobuf::libprotoc
Event though
find_package(Protobuf REQUIRED)
Works just fine.
I read I'm supposed to run cmake ../.. -DBUILD_DEPS=ON -DBUILD_SHARED_LIBS=ON to solve this. However that results in:
CMake Error at cmake/abseil-cpp.cmake:38 (find_package):
Could not find a package configuration file provided by "absl" with any of
the following names:
abslConfig.cmake
absl-config.cmake
Add the installation prefix of "absl" to CMAKE_PREFIX_PATH or set
"absl_DIR" to a directory containing one of the above files. If "absl"
provides a separate development package or SDK, be sure it has been
installed.
Call Stack (most recent call first):
CMakeLists.txt:191 (include)
-- Configuring incomplete, errors occurred!
See also "/home/ray/CLionProjects/grpc/grpc/CMakeFiles/CMakeOutput.log".
See also "/home/ray/CLionProjects/grpc/grpc/CMakeFiles/CMakeError.log".
Content of /usr/lib64/cmake/grpc/gRPCConfig.cmake
# Module path
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/modules)
# Depend packages
# Targets
include(${CMAKE_CURRENT_LIST_DIR}/gRPCTargets.cmake)
The problem is actually with the project you use via find_package() and with its package file (/usr/lib64/cmake/grpc/gRPCConfig.cmake in your case). The error message
The following imported targets are referenced, but are missing:
means, that the package file references IMPORTED targets but they are never defined.
The usual reason for that problem is following:
During its own build, the project uses find_package() for some other packages. This find_package() call defines IMPORTED targets, which are used in the project for link.
Its package file includes the script(s), which is created by install(EXPORT) command and filled according to install(TARGETS ... EXPORT ...) command. This included script uses IMPORTED targets, but doesn't define them.
The project's package file forgets to use find_package, or, better, find_dependency for define the IMPORTED target for the included scripts.
If you don't want to fix the (other) project's package file, then the most direct solution is to add missed find_package into your own project:
# Hack: This will define IMPORTED targets, needed for gRPC project, but not defined by it.
find_package(Protobuf REQUIRED)
# Now perform the original 'find_package' call.
find_package(gRPC CONFIG REQUIRED)
Actually, gRPCConfig.cmake package file was intended to contain the call find_package(Protobuf). Its template cmake/gRPCConfig.cmake.in is following:
# Module path
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/modules)
# Depend packages
#_gRPC_FIND_ZLIB#
#_gRPC_FIND_PROTOBUF#
#_gRPC_FIND_SSL#
#_gRPC_FIND_CARES#
#_gRPC_FIND_ABSL#
# Targets
include(${CMAKE_CURRENT_LIST_DIR}/gRPCTargets.cmake)
and on substitution the variable _gRPC_FIND_PROTOBUF should emit the following code:
if(NOT Protobuf_FOUND AND NOT PROTOBUF_FOUND)
find_package(Protobuf ${gRPC_PROTOBUF_PACKAGE_TYPE})
endif()
(the variable should be set in cmake/protobuf.cmake).
But something goes wrong, and the resulted /usr/lib64/cmake/grpc/gRPCConfig.cmake contains the empty variable's substitution:
# Module path
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/modules)
# Depend packages
# Targets
include(${CMAKE_CURRENT_LIST_DIR}/gRPCTargets.cmake)