如何使用Git子模块和CMake处理传递依赖冲突? [英] How to handle a transitive dependency conflict using Git submodules and CMake?

查看:211
本文介绍了如何使用Git子模块和CMake处理传递依赖冲突?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有许多Git存储库,其中一些包含我们自己的代码,而另一些包含稍微修改的第三方库代码。简化的依赖关系图如下所示:

We have a number of Git repositories, some containing our own code and some containing slightly modified third-party library code. A simplified dependency graph looks like this:

  executable_A
    |     |
    |     v
    |  library_B
    |     |
    v     v
   library_C

因此可执行文件对 library_C ,一个直接和一个可传递。我希望使用Git子模块和CMake将它们结合在一起,因此简化的目录结构如下所示:

So the executable has two dependencies on library_C, one direct and one transitive. I am hoping to tie this all together using Git submodules and CMake, so a simplified directory structure looks like this:

executable_A/
  CMakeListst.txt
  library_B/
    CMakeLists.txt
    library_C/
      CMakeLists.txt
  library_C/
    CMakeLists.txt

如您所见, library_C 存储库作为子模块包含在内两次。让我们假设两个子模块都指向相同的提交(关于如何强制执行的任何想法都会受到欢迎,但不是这个问题的主题)。

As you can see, the library_C repository is included as a submodule twice. Let's assume that both submodules are pointing at the same commit (any ideas about how to enforce that would be welcome, but are not the topic of this question).

重新使用 add_subdirectory target_link_libraries target_include_directories 来管理这些相互依赖性。相当标准。

We're using add_subdirectory, target_link_libraries and target_include_directories to manage these interdependencies. Pretty standard.

问题在于,如果两次创建同名目标,CMake会不喜欢它,因此会抱怨:

The problem is that CMake doesn't like it if you create a target with the same name twice, so it complains:


CMake在library_C / CMakeLists.txt:13(add_library):

add_library无法创建目标 library_C,因为另一个目标
具有相同名称的人已经存在。现有目标是在源目录 ... / library_B / library_C中创建的静态
库。

有关详细信息,请参阅策略CMP0002的文档。

CMake Error at library_C/CMakeLists.txt:13 (add_library):
add_library cannot create target "library_C" because another target with the same name already exists. The existing target is a static library created in source directory ".../library_B/library_C".
See documentation for policy CMP0002 for more details.

我宁愿不删除 executable_A library_C ,因为它是通过 library_B 插入的事实是 library_B 的实现细节,不应依靠。而且,一旦添加了另一个依赖项,例如 executable_A->,此方法就会失效。 library_D-> library_C

I'd rather not remove the direct dependency of executable_A on library_C, because the fact that it is pulled in via library_B is an implementation detail of library_B that should not be relied on. Moreover, this approach will break down as soon as we add another dependency like executable_A --> library_D --> library_C.

是我所能找到的最接近的问题,但它更笼统,反正仍然没有得到回答。)

(This question is the closest I could find, but is a bit more general and remains unanswered anyway.)

推荐答案

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

There are several approaches for detect and discard inclusion of the project, which has already be included in some other parts of the main project.

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

The simplest pattern for single inclusion of subproject is checking existence of some subproject's target:

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

(此处假定项目 C 定义目标 library_C 。)

(Here we assume that project C defines target library_C.)

在这样的条件包含之后,所有子项目的目标和功能将成为立即与呼叫者保持联系

After such conditional inclusion all subproject's targets and functions will be immediately available for the caller with garantee.

最好在所有地方使用此模式(在 executable_A library_B )。在 executable_A 中更改 library_B library_C 的顺序不会破坏正确性。

It is better to use this pattern in all places (in executable_A and library_B). Such a way changing order of library_B and library_C in executable_A doesn't break correctness.

可以对子项目本身重新使用此模式:

This pattern can be reworked for use by subproject itself:

# 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 就在其中。请注意,此变量是 cached ,因此,第二次调用 cmake 时(例如,如果某些 CMakeLists.txt 已更改),该变量一开始就存在。


Check project existence

When a project is created, CMake defines several variables for it, and <PROJECT-NAME>_BINARY_DIR is among them. Note, that this variable is cached, so when cmake is called the second time (e.g. if some of CMakeLists.txt has been changed), the variable exists at the very beginning.

# 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()

此模式可以重新设计以供子项目本身使用:

This pattern can be reworked for use by subproject itself:

# 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()

这篇关于如何使用Git子模块和CMake处理传递依赖冲突?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆