簡體   English   中英

如何使用 Git 子模塊和 CMake 處理傳遞依賴沖突?

[英]How to handle a transitive dependency conflict using Git submodules and 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:13 (add_library) 處的 CMake 錯誤:
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 。)

在這種有條件的包含之后,所有子項目的目標和功能將立即可供調用者使用 garantee

最好在所有地方(在executable_Alibrary_B )使用這種模式。 這種在executable_A library_C中更改library_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()

CMake 3.10 及更高版本現在支持:

include_guard(GLOBAL)

類似於 C++ 中的 #pragma once。

Craig Scott 所著的《Professional CMAKE, A Practical Guide》是一本關於 cmake 的好書,對我解釋了很多。 僅可在線訪問:[ https://crascit.com/professional-cmake/][1]

我不是 Craig,但他的書對像我這樣的 cmake 新手來說是一項很好的服務。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM