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.
Related
We are using cmake and started using conan as a package manager.
Before conan however prebuild 3rd Party libs like GTest where added via
find_package(GTest REQUIRED). (By adding custom find Scripts for each library find_package() was able to locate our prebuild third parties)
In the new conan way it's pretty easy to add 3rd parties to a library
add_library(myLib sources)
target_link_libraries(myLib PRIVATE GTEST::GTEST)
To achieve backwards compatibility i need to create a target with the name GTest::GTest from the find_package().
Now the question is how can i create a new target from the find_package() result?
I did try to create a new dummy target
find_package(GTest REQUIRED)
add_library("GTest" "foo.cpp")
target_link_libraries("GTest" PUBLIC "${GTest_LIBRARIES}")
add_library("GTEST::GTEST" ALIAS GTest)
where foo.cpp is just an empty file.
when linking against the target GTEST::GTEST
this results in a linker error GTEST_1_0d.lib was not found
How would you create a cmake target from prebuild binaries?
Could you help me out here?
Edit: Sorry for beeing unclear.
I do not want to touch legacy systems. Therefore Conan is not available on legacy systems.
The question is: How can I create targets from precompiled libraries that look exactly like Conan targets
To achieve backwards compatibility i need to create a target with the name GTest::GTest from the find_package(). Now the question is how can i create a new target from the find_package() result?
As you say, the result of your call to find_package(GTest) is that GTEST::GTEST is created. So just write
add_library(GTest::GTest ALIAS GTEST::GTEST)
If you have code that needs to use the other name, no?
On the other hand:
find_package(GTest REQUIRED)
If the result of your call to find_package(GTest) is the ancient built-in CMake module, then something like this might work:
find_package(GTest REQUIRED)
# Not using Conan
if (NOT TARGET GTEST::GTEST)
if (TARGET GTest::gtest)
# CMake 3.20+ module in use
add_library(GTEST::GTEST ALIAS GTest::gtest)
elseif (TARGET GTest::GTest)
# CMake 3.5+ module in use
add_library(GTEST::GTEST ALIAS GTest::GTest)
else ()
add_library(GTEST::GTEST IMPORTED INTERFACE)
target_include_directories(GTEST::GTEST INTERFACE "${GTEST_INCLUDE_DIRS}")
target_link_libraries(GTEST::GTEST INTERFACE "${GTEST_LIBRARIES}")
endif ()
endif ()
You can decide whether to add GTest::gtest_main, GTest::Main, or use ${GTEST_BOTH_LIBRARIES} in each of the three respective branches.
I'm using CMake to build and to install a certain library, foo.
My library depends on some other library, bar, which has a config CMake script, so I have:
find_package(bar REQUIRED)
target_link_libraries(foo PUBLIC bar::bar)
That's as far as building goes. For installation, I have appropriate install() commands, with exports, and version configuration and all that stuff. This generates the package's -config.cmake file (as well as a version config file), so I don't need to keep one in the repository, nor generate one line-by-line within my CMakeLists.txt
Now, CMake has a module named find_dependency(), whose documentation suggests is to be used in package configuration files. But - I don't explicitly add it there. Should I? And more generally: Under which circumstances should I manually ensure a package configuration file has a find_dependency() for various find_package()'s?
First, CMake does not support "Transitive" behavior for find_package() (check this question).
The documentation recommends that "All REQUIRED dependencies of a package should be found in the Config.cmake file":
# <package>Config.cmake file
include(CMakeFindDependencyMacro)
find_dependency(Stats 2.6.4)
include("${CMAKE_CURRENT_LIST_DIR}/ClimbingStatsTargets.cmake") # They depend on Stats
include("${CMAKE_CURRENT_LIST_DIR}/ClimbingStatsMacros.cmake")
So, answering your questions:
"I don't explicitly add it there. Should I?" You actually have to, at least for REQUIRED packages.
"Under which circumstances should I manually ensure a package configuration file has a find_dependency() for various find_package()'s?" For required packages, you must. For optional package, you might want to add it in the configuration file so that optional features will be available.
I am working on a project which depends on an external package (Catch2). In my top level CMakelists.txt I have:
# Top level CMakelists.txt
set(Catch2_DIR "${PATH_TO_CATCH2}/lib/cmake/Catch2/")
find_package(Catch2 ${CATCH2_VERSION} REQUIRED)
Then I added the following to my package configuration file:
# <package>Config.cmake file
include(CMakeFindDependencyMacro)
set(Catch2_DIR "#PATH_TO_CATCH2#/lib/cmake/Catch2/") #be careful, path hard coded
find_dependency(Catch2 REQUIRED)
Just be careful because the find_dependency is a macro and it will change the value of PACKAGE_PREFIX_DIR variable in your package configuration file.
I added the xgboost library as a git submodule of my project and I'm trying to add it to cmake as a subdirectory. Unfortunately it's not working. A simple hello world project with the following CMakeLists.txt replicates the error that I'm getting.
cmake_minimum_required(VERSION 3.2)
project(foo)
add_subdirectory(xgboost)
add_executable(${PROJECT_NAME} foo.cpp)
target_link_libraries(${PROJECT_NAME} xgboost)
After building the library there is nothing in the xgboost/lib directory so I get the following error.
clang: error: no such file or directory:
'/Users/.../myproject/xgboost/lib/libxgboost.dylib'
I think that the problem is generated in their CMakeLists file since they have two different targets. Maybe cmake is choosing the wrong target but I'm not familiar enough with cmake to figure it out. The following code is from xgboost's CMakeLists.
# Executable
add_executable(runxgboost $<TARGET_OBJECTS:objxgboost> src/cli_main.cc)
set_target_properties(runxgboost PROPERTIES
OUTPUT_NAME xgboost
)
set_output_directory(runxgboost ${PROJECT_SOURCE_DIR})
target_link_libraries(runxgboost ${LINK_LIBRARIES})
# Shared library
add_library(xgboost SHARED $<TARGET_OBJECTS:objxgboost>)
target_link_libraries(xgboost ${LINK_LIBRARIES})
set_output_directory(xgboost ${PROJECT_SOURCE_DIR}/lib)
#Ensure these two targets do not build simultaneously, as they produce outputs with conflicting names
add_dependencies(xgboost runxgboost)
My questions in order of importance are:
Is there any way to fix it without modifying xgboost's CMakeLists.txt file?
Is it reasonable to try to add xgboost to my project as a git submodule?
Is there any reason cmake is not instructing to build the library?
Note: There were several edits to this question since I tried to narrow down the problem and to provide more information.
(I would love to ask for few things beforehand in the comment section, but I have too low reputation to do so, so I will just give it a shot ;))
I have few suspects, and one of them is ${CMAKE_SOURCE_DIR} of the submodule's root CMakeLists.txt. Although the paths are set properly when you run that CMakeLists.txt alone, cmake gets confused the moment you add it as your subdirectory. Have you looked into another directories for your output binaries?
First I would suggest testing this hypothesis, and then I would suggest writing similar, but separate CMakeLists.txt file for xgboost library, and then substitute it in the project temporarily. Unfortunately the CMakeLists.txt filename is hardcoded and there is no possibility to have two files of that kind in one directory; so it seems that the answer to 1) is, that you rather have to change the file.
For the 2): as long as it does not require huge additional logic in your CMakeLists.txt, it makes sense. Other viable option is to create an install target, which you can use to install your xgboost library locally (using CMAKE_INSTALL_PREFIX(doc) variable), and then add the installation path to your CMAKE_LIBRARY_PATH(doc).
I'm trying to manage my C++ project dependencies using CMake and gitsubmodules. I'm following the layout described here: http://foonathan.net/blog/2016/07/07/cmake-dependency-handling.html and it's worked really well for me on smaller projects. But I've started to use it on much larger projects and I'm hitting some issue with CMake.
My current setup
All my external build dependencies are in a contrib/ subfolder inside my main project. Each is a submodule and has its own separate directory.
/contrib
- /eigen
- /curl
- /leapserial
- /zlib
- /opencv
etc.
The contrib/CMakeListst.txt simply initializes the submodule and adds the subdirectory for each external dependency
# EIGEN
execute_process(COMMAND git submodule update --recursive --init -- eigen
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
# options..
add_subdirectory(eigen EXCLUDE_FROM_ALL)
# CURL
execute_process(COMMAND git submodule update --recursive --init -- curl
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
# Initialize cache with CMake build options..
add_subdirectory(curl EXCLUDE_FROM_ALL)
# LEAP SERIAL
execute_process(COMMAND git submodule update --recursive --init -- leapserial
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
# Initialize cache with CMake build options..
add_subdirectory(leapserial EXCLUDE_FROM_ALL)
# ZLIB
execute_process(COMMAND git submodule update --recursive --init -- zlib
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
# Initialize cache with CMake build options..
add_subdirectory(zlib EXCLUDE_FROM_ALL)
# OPENCV
execute_process(COMMAND git submodule update --recursive --init -- opencv
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
# Initialize cache with CMake build options..
add_subdirectory(opencv EXCLUDE_FROM_ALL)
This setup has worked fantastically for me:
It's system/packagemanager independent. You don't need to install any libraries to get started developing
I can maintain the exact versions of my dependencies by setting the submodule to a particular commit. There are no surprises with some external library breaking your build
Adding the libraries to my build in the root CMakeListst.txt is trivial. Since I have the target available I just have something like
add_executable(someProjectImWorkingOn
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp )
target_link_libraries(someProjectImWorkingOn
opencv_world
eigen
zlib
etc.)
when you hook up an existing library target to your own target executable/library CMake will automatically (through the target interface) add include directories to your target and add any other necessary options the library target requires for it to be used
I can pick a toolchain/compiler-option/build-type in the root CMakeLists.txt and it'll propogate to all the subprojects (I need to build for multiple systems. So this is a big big deal)
Since it's all in one "mega-project" it makes it very easy to hook up to rtags/kdevelop/clion to navigate not on your own code, but also the library code
Some issues that I can't resolved:
1
Subdirectories will define targets with the same name. In the example I gave, both Eigen OpenCV as well as another library define an 'uninstall' target
I tried to update the
add_subdirectory(blah)
to
add_subdirectory(blah EXCLUDE_FROM_ALL)
but this doesn't fix the issue for some reason
Enabling the variable ALLOW_DUPLICATE_CUSTOM_TARGETS kinda works.. but this is a hack, only work with Make files, and the libraries are essentially still "mixing" so it's still an issue
2
The second issue came up in LeapSerial but illustrates a bigger issue. The project no longer knows it's own name. LeapSerial tried to determine the version of LeapSerial, but when it asks for the project version it's getting the root project version. Ie. when cmake code in a subproject asks for "what project am I in" it's getting the root project, and not the immediate project it's in.
So again, the parent "namespace"s are leaking everywhere. This is bound to create more and more issues down the line. I need to the submodules to be self-contained
Is there are a cleaner solution?
ExternalProjectAdd might solve some of these problems, but has a lot more issues of its own. It's a real non-starter b/c it doesn't do most of what I've listed. The central issue is that it doesn't expose the sub-project's targets - and just vomits back variables that you then have to juggle
As the asker said in the comments, they resolved their issue by using the Hunter package manager. The rest of this answer is about actually answering the question as posed.
Concerning your first issue with target name clashes when using add_subdirectory-based approaches to using dependencies, a very similar (or essentially the same?) question has also since been asked here: How to avoid namespace collision when using CMake FetchContent?. When the clashes are between targets from different project dependencies, there's nothing you can do right now except politely ask the project maintainers to consider modifying their non-import/export target names to be namespaced like.
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).
Concerning your second issue, there's not enough detail in your question post to confidently troubleshoot. What is LeapSerial? Are you referring to the leapmotion/leapserial GitHub repo? What version and what commit are you referring to? At the latest commit before the time of your question post, 41515db, it's not immediately obvious what's wrong.
Variables in CMake are scoped by directory, so even if a project is added by add_subdirectory and doesn't used the <PROJECT-NAME>_VERSION variable and instead uses the more general PROJECT_VERSION variable, it should be okay. It just shouldn't attempt to use the CMAKE_PROJECT_VERSION variable to get its own version, since that one is fixed to refer to the top-level project's version.
I am new to CMake and DBus. I am following along the guide here and make a basic program compile and execute.
The first problem that I ran into was my program will not find
<dbus/dbus.h>
I got around that issue by adding some include directories to my CMakeList.txt.
Currently, my CMakeLists.txt looks like this:
...
include_directories(/usr/lib/)
include_directories(/usr/include/dbus-1.0/)
include_directories(/usr/lib/x86_64-linux-gnu/dbus-1.0/include)
include_directories(/usr/include/glib-2.0)
include_directories(/usr/lib/x86_64-linux-gnu/glib-2.0/include/)
set (LIBS
dbus-1
dbus-glib-1
)
add_executable(mydbus mydbus.cpp)
target_link_libraries(mydbus ${LIBS} )
Now, my program is complaining about not being able to find dbus-arch-deps.h
/usr/include/dbus-1.0/dbus/dbus.h:29:33: fatal error: dbus/dbus-arch-deps.h: No such file or directory
#include <dbus/dbus-arch-deps.h>
I know that the solution for this is to use proper command line flags or pkg-config. As discussed here and numerous other posts.
However, I do not know how to configure CMakeLists.txt to have similar effect.
My guess would be to add something like find_package(dbus-1) to CMakeLists.txt. And if that is correct, I am going to have to write my own Finddbus-1.cmake. Does this sound correct? Or is there an easier way?
I will appreciate any pointers.
You may get an existing FindDBus.cmake script (e.g., this one), copy it into your project, and use as
find_package(DBus REQUIRED)
# Use results of find_package() call.
include_directories(${DBUS_INCLUDE_DIRS})
add_executable(mydbus mydbus.cpp)
target_link_libraries(mydbus ${DBUS_LIBRARIES})
Alternatively, as you know pkgconfig can find DBus, you may use CMake module PkgConfig. Actually, FindDBus.cmake script, referenced above, uses PkgConfig module in its implementation. Possible usage could be:
find_package(PkgConfig REQUIRED) # Include functions provided by PkgConfig module.
pkg_check_modules(DBUS REQUIRED dbus-1) # This calls pkgconfig with appropriate arguments
# Use results of pkg_check_modules() call.
include_directories(${DBUS_INCLUDE_DIRS})
link_directories(${DBUS_LIBRARY_DIRS})
add_executable(mydbus mydbus.cpp)
target_link_libraries(mydbus ${DBUS_LIBRARIES})
However, using link_directories is not recommended, it is better to use absolute paths to libraries in target_link_libraries() call. That is why it is better to combine pkg_check_modules with find_library, as it is done in the referenced Find script. That answer describes generic way for use result of pkgconfig in CMake.