如何使用Git子模块和CMake处理传递依赖冲突?

我们有许多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_subdirectorytarget_link_librariestarget_include_directories来管理这些相互依赖关系。 相当标准。

问题是如果你用相同的名字创建一个目标两次,CMake不喜欢它,所以它抱怨:

library_C / CMakeLists.txt中的CMake错误:13(add_library):
add_library无法创建目标“library_C”,因为已存在另一个具有相同名称的目标。 现有目标是在源目录“... / library_B / library_C”中创建的静态库。
有关更多详细信息,请参阅策略CMP0002的文档。

我宁愿不删除的直接依赖executable_Alibrary_C ,因为它是通过拉一个事实library_B是一个实现细节library_B不应加以依赖。 而且,只要我们添加像executable_A --> library_D --> library_C这样的其他依赖项,这种方法就会崩溃。

(这个问题是我能找到的最接近的,但是更一般,仍然没有答案。)


有几种检测和丢弃项目的方法,已经包含在主项目的其他部分。

检查项目的目标存在

子项目单个包含的最简单模式是检查是否存在某个子项目的目标:

# When include 'C' subproject
if(NOT TARGET library_C)
    add_subdirectory(C)
endif()

(在这里我们假定项目C定义了目标库library_C 。)

在这样的条件包含之后,所有子项目的目标和功能将立即可用于提供保证的呼叫者。

最好在所有地方使用这种模式(在executable_Alibrary_B )。 这样改变executable_Alibrary_Blibrary_C顺序并不会破坏正确性。

这种模式可以重新使用,以供子项目本身使用:

# 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()
链接地址: http://www.djcxy.com/p/95823.html

上一篇: How to handle a transitive dependency conflict using Git submodules and CMake?

下一篇: Eclipse fails to open .vue files in Web Page Editor