我正在尝试使用 CMake 和 gitsubmodules 管理我的 C++ 项目依赖项。我遵循此处描述的布局:http://foonathan.net/blog/2016/07/07/cmake-dependency-handling.html在较小的项目中,它对我来说非常有效。但我已经开始在更大的项目中使用它,但我遇到了 CMake 的一些问题。
我目前的设置
我所有的外部构建依赖项都在我的主项目中的 contrib/
子文件夹中。每个都是一个子模块,并有自己单独的目录。
/contrib
- /eigen
- /curl
- /leapserial
- /zlib
- /opencv
etc.
contrib/CMakeListst.txt
只是初始化子模块并为每个外部依赖添加子目录
# 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)
这个设置对我来说非常有效:
- 它独立于系统/包管理器。您无需安装任何库即可开始开发
- 我可以通过将子模块设置为特定的提交来维护我的依赖项的确切版本。一些外部库破坏你的构建并不奇怪
- 将库添加到我在根
CMakeListst.txt
中的构建是微不足道的。因为我有可用的目标,所以我只有类似的东西
add_executable(someProjectImWorkingOn
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp )
target_link_libraries(someProjectImWorkingOn
opencv_world
eigen
zlib
etc.)
- 当您将现有的库目标连接到您自己的目标可执行文件/库时,CMake 将自动(通过目标接口(interface))将包含目录添加到您的目标并添加库目标使用它所需的任何其他必要选项<
- 我可以在根 CMakeLists.txt 中选择一个工具链/编译器选项/构建类型,它会传播到所有子项目(我需要为多个系统构建。所以这是一个大问题)<
- 因为它都在一个“大型项目”中,所以很容易连接到 rtags/kdevelop/clion 来导航,而不是在您自己的代码上,也可以在库代码上导航
一些我无法解决的问题:
1
子目录将定义具有相同名称的目标。在我给出的示例中,Eigen OpenCV 和另一个库都定义了一个“卸载”目标
我试着更新了
add_subdirectory(blah)
到
add_subdirectory(blah EXCLUDE_FROM_ALL)
但由于某种原因这并不能解决问题
启用变量 ALLOW_DUPLICATE_CUSTOM_TARGETS
有点管用..但这是一个 hack,只适用于 Make 文件,库基本上仍在“混合”,所以它仍然是一个问题
2
第二个问题出现在 LeapSerial 中,但说明了一个更大的问题。该项目不再知道它自己的名字。 LeapSerial 试图确定 LeapSerial 的版本,但是当它询问项目版本时,它得到的是根项目版本。 IE。当子项目中的 cmake 代码询问“我在哪个项目中”时,它获取的是根项目,而不是它所在的直接项目。
因此,父“命名空间”又一次到处泄漏。这势必会产生越来越多的问题。我需要子模块是独立的
是否有更清洁的解决方案?
ExternalProjectAdd 可能会解决其中的一些问题,但它本身还有很多很多问题。这是一个真正的非入门 b/c,它没有完成我列出的大部分内容。核心问题是它不公开子项目的目标 - 只是吐出你必须处理的变量
最佳答案
正如提问者在评论中所说,他们通过使用 Hunter 包管理器解决了他们的问题。这个答案的其余部分是关于实际回答所提出的问题。
关于使用 add_subdirectory
时目标名称冲突的第一个问题基于使用依赖项的方法,一个非常相似(或基本相同?)的问题也被问到 here: How to avoid namespace collision when using CMake FetchContent? .当来自不同项目依赖项的目标之间发生冲突时,您现在无能为力,只能礼貌地要求项目维护者考虑修改他们的非导入/导出目标名称,使其具有命名空间。
例如,对于库目标,它可能看起来像:
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::" ...)
有 a Kitware issue ticket by Craig Scott proposing a CMake feature for Project-level namespaces .以下是摘录:
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).
有时上游维护者会拒绝支持 add_subdirectory
/FetchContent
用例。 OpenCV就是这样,如图this issue ticket (#16896) .至于本征,有 an open ticket that hasn't had any activity in a while (#1892) .
关于您的第二个问题,您的问题帖子中没有足够的细节来自信地进行故障排除。什么是 LeapSerial?你指的是 the leapmotion/leapserial
GitHub repo ?您指的是什么版本和什么提交?在您的问题发布之前的最新提交,41515db , 不是很明显出了什么问题。
CMake 中的变量是按目录确定范围的,所以即使项目是由 add_subdirectory
添加的并且没有使用 <PROJECT-NAME>_VERSION
变量,而是使用更通用的 PROJECT_VERSION
变量,应该没问题。它只是不应该尝试使用 CMAKE_PROJECT_VERSION
变量以获取其自己的版本,因为该版本已固定为引用顶级项目的版本。
关于c++ - 在 CMake 中隔离 gitsubmodule 项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45688707/