[英]cmake propagate dependencies using find_package
舉一個簡單的例子:有兩個庫和一個可執行文件。 兩個庫都是SHARED
(即 .so 文件)。 一種稱為libMain ,一種稱為libUtil 。 libMain使用libUtil ,可執行文件也是如此。 可執行文件可能會單獨使用libUtil ,但通常它會調用libMain中的一個方法,該方法在其實現中確實使用了libUtil 。
所以在閱讀了一些關於 CMake 的教程和文檔之后,這個例子看起來相當簡單。 每個項目都有一個簡單的 CMakeLists.txt,而libUtil鏈接到libMain ,可執行鏈接到libMain 。 (我省略了target_include_directories
以節省一些行)所有項目都使用相同的 PREFIX_PATH。
include(GNUInstallDirs)
project(libUtil)
set(CMAKE_SHARED_LIBRARY_PREFIX "")
add_library(libUtil SHARED main.cpp)
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Config
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(EXPORT ${PROJECT_NAME}Config DESTINATION ${CMAKE_INSTALL_PREFIX}/cmake)
include(GNUInstallDirs)
project(libMain)
set(CMAKE_SHARED_LIBRARY_PREFIX "")
add_library(libUtil SHARED main.cpp)
find_package(libUtil REQUIRED)
target_link_libraries(${PROJECT_NAME} PUBLIC libUtil)
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Config
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(EXPORT ${PROJECT_NAME}Config DESTINATION ${CMAKE_INSTALL_PREFIX}/cmake)
project(exe)
find_package(libMain REQUIRED)
set(CMAKE_SHARED_LIBRARY_PREFIX "")
add_executable(exe main.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE libMain)
但是,在構建可執行文件時,我最終遇到了鏈接器錯誤,告訴 exe無法執行 -llibUtil 。
我已經花了很多時間,在閱讀了幾篇文章后,我發現(或者至少我這么認為......)我需要提供一個自定義的 libMainConfig.cmake (我將生成的重命名為 libMainTargets.cmake)
include("${CMAKE_CURRENT_LIST_DIR}/libMainTargets.cmake")
find_package(libUtil REQUIRED)
鏈接器錯誤現在消失了,我可以運行我的項目。 我仍然不明白為什么我需要這樣做。 我知道處理已經構建的庫時存在差異。 然而,由於 CMake 總是使用基於目錄的項目分離,我如何以及為什么要在同一個 CMakeLists.txt 中構建多個項目? 到目前為止,我一直使用find_package
(它本質上是 add_library IMPORTED,即搜索預構建庫,如果我沒記錯的話)並希望將其定義的依賴項傳播到“消費”項目。 但似乎來自導入目標的所有PUBLIC
、 INTERFACE
和PRIVATE
對“消費”目標沒有影響?
請在解釋中詳細說明和/或指出我遺漏的一些參考資料,並指出一些最佳實踐,假設所有項目要么由我自己構建,要么是像 boost 或 JNI 這樣的系統庫。
謝謝!
CMake 有一個特定的函數來傳播find_package
這樣的稱為find_dependency
。 你可以這樣使用它:
include(CMakeFindDependencyMacro)
find_dependency(libutil)
CMake 不會在其生成的文件中導出調用find_package
。 您必須使用find_package
或find_dependency
手動執行此操作。 不同之處在於find_dependency
將正確轉發REQUIRED
和QUIET
。
-llibUtil
發送到鏈接器? 向target_link_libraries
添加內容時,有兩種情況:
-l
標志。 由於鏈接到libutil
是一個公共財產libmain
,所有消費者libmain
也將鏈接到libutil
。
由於調用 find 包必須手動完成,因此libutil
不是目標。 假設鏈接到系統庫,因此 CMake 會將exe
到名為libutil
的系統庫,該庫不存在。
調用find_package(libUtil REQUIRED)
將確保exe
通過鏈接目標而不是庫來消耗libutil
的使用要求。
libUtil
如何成為目標? CMake 目標不(完全)綁定到目錄。 您可以擁有GLOBAL
和IMPORTED
目標,也可以按項目擁有多個目標。 想象一個由多個庫和可執行文件組成的項目。 一個類比是 CMake 項目是 Visual Studio 解決方案,而 CMake 目標是 Visual Studio 項目。
現在在導入的目標上。 它們旨在表示已由另一個項目編譯的目標,您安裝或導出了構建樹。 導入的目標讓你可以像普通目標一樣使用來自不同項目的東西,就好像你聲明了它一樣。 導入的目標比編譯器標志更精確:它們當然攜帶庫,但也攜帶如何鏈接、所需的編譯器標志、包含目錄和其他要求。
find_package
和find_dependency
用於查找配置文件,這些文件包含導入的目標信息。 之后,只需鏈接到它就會設置包含目錄、正確的鏈接器標志等。
導出多個目標的項目的一個很好的例子是 SFML,它將聲音、圖形和窗口管理等不同模塊導出為不同的靜態/動態庫。
CMake 讓我們為目標使用命名空間。 使用命名空間語法時,不能是系統庫。 CMake 將輸出未找到目標的錯誤,而不是嘗試鏈接到不存在的庫。
install(
EXPORT ${PROJECT_NAME}Config
NAMESPACE libUtil
DESTINATION ${CMAKE_INSTALL_PREFIX}/cmake
)
然后將鏈接更改為:
target_link_libraries(${PROJECT_NAME} PUBLIC libUtil::libUtil)
命名空間名稱的約定是使用與包相同的名稱。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.