我们有许多Git存储库,其中一些包含我们自己的代码,另一些包含稍微修改过的第三方库代码。简化的依赖关系图如下所示:
executable_A
| |
| v
| library_B
| |
v v
library_C
因此,可执行文件在library_C
上有两个依赖项,一个是直接的,一个是传递的。我希望使用Git子模块和CMake将它们组合在一起,因此简化的目录结构如下所示:
executable_A/
CMakeListst.txt
library_B/
CMakeLists.txt
library_C/
CMakeLists.txt
library_C/
CMakeLists.txt
如您所见,library_C
存储库作为子模块包含两次。让我们假设两个子模块都指向同一个提交(关于如何强制执行的任何想法都是受欢迎的,但不是这个问题的主题。)
我们正在使用add_subdirectory
,target_link_libraries
和target_include_directories
来管理这些相互依赖关系。很标准。
问题在于,如果你创建一个具有相同名称的目标两次,那么CMake并不喜欢它,所以它会抱怨:
library_C / CMakeLists.txt的CMake错误:13(add_library):
add_library无法创建目标" library_C"因为另一个目标 具有相同的名称已经存在。现有目标是静态的 在源目录中创建的库" ... / library_B / library_C"。
有关更多详细信息,请参阅策略CMP0002的文档。
我宁愿不删除executable_A
对library_C
的直接依赖,因为它是通过library_B
引入的,这是library_B
的实现细节这不应该依赖。此外,一旦我们添加了另一个依赖项executable_A --> library_D --> library_C
。
(This question是我能找到的最接近的,但是更为一般,但无论如何都没有答案。)
答案 0 :(得分:11)
有几种方法可以检测和丢弃项目的包含,已经包含在主项目的其他部分中。
单项包含子项目的最简单模式是检查某个子项目的目标是否存在:
# When include 'C' subproject
if(NOT TARGET library_C)
add_subdirectory(C)
endif()
(这里我们假设项目C
定义了目标library_C
。)
在有条件包含后,所有子项目的目标和功能将立即可用,以便呼叫者保证。
最好在所有地方(executable_A
和library_B
)使用此模式。这样改变library_B
中library_C
和executable_A
的顺序并不会破坏正确性。
此模式可以重新设计以供子项目本身使用:
# At the beginning of 'C' project
cmake_minimum_required(...)
if(TARGET library_C)
return() # The project has already been built.
endif()
project(C)
...
创建项目时,CMake为其定义了几个变量,其中包含<PROJECT-NAME>_BINARY_DIR。请注意,此变量是缓存,因此当第二次调用cmake
时(例如,如果某些CMakeLists.txt
已被更改),变量一开始就存在。
# When include 'C' subproject
if(NOT C_BINARY_DIR # Check that the subproject has never been included
OR C_BINARY_DIR STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/C" # Or has been included by us.
)
add_subdirectory(C)
endif()
此模式可以重新设计以供子项目本身使用:
# At the beginning of 'C' project
cmake_minimum_required(...)
if(NOT C_BINARY_DIR # Check that the project has never been created
OR C_BINARY_DIR STREQUAL "${CMAKE_CURRENT_BINARY_DIR}" # Or has been created by us.
project(C)
else()
return() # The project has already been built
endif()
答案 1 :(得分:0)
CMake 3.10及更高版本现在支持:
include_guard(GLOBAL)
类似于c ++中的#pragma。
Craig Scott撰写的一本关于cmake的很棒的书对我解释了很多东西。仅在以下位置在线可用: [https://crascit.com/professional-cmake/][1]
我不是克雷格,但他的书对宣告像我这样的新来者很有帮助。