[英]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_subdirectory
、 target_link_libraries
和target_include_directories
來管理這些相互依賴關系。 很標准。
問題是 CMake 不喜歡如果你創建一個同名的目標兩次,所以它會抱怨:
library_C/CMakeLists.txt:13 (add_library) 處的 CMake 錯誤:
add_library 無法創建目標“library_C”,因為另一個具有相同名稱的目標已經存在。 現有目標是在源目錄“.../library_B/library_C”中創建的靜態庫。
有關更多詳細信息,請參閱策略 CMP0002 的文檔。
我寧願不刪除的直接依賴executable_A
上library_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_A
和library_B
)使用這種模式。 這種在executable_A
library_C
中更改library_B
和library_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.