2017-10-12 35 views
0

給定一個具有「app」和「lib」兄弟目錄的項目,其中「app」根據由「lib」構建的(靜態)庫構建可執行文件。我想要的是普通構建過程僅構建庫的情況,但如果構建「應用程序」,則構建「庫」和「應用程序」。鏈接建立靜態庫,而不是使用add_subdirectory?

什麼我目前做的是現在,在app,包括我libadd_subdirectory,但是由於各種原因,這是通過一種機制,我不拉在lib的間接依賴到鏈接線的所有意識到。我想就像是讓我的應用程序只是建立libmylib.alibmylib.pc,然後app可以只從libmylib.pc(或手動指定它)計算自己的連接線,但我不知道如何完成。

這裏有一個最低工作的例子,我已經有了設立現在:

的lib /的CMakeLists.txt

cmake_minimum_required(VERSION 3.8.0) 
project(mylib CXX) 

find_package(PkgConfig REQUIRED) 
pkg_check_modules("mylib" "libssl") 

find_package(Boost REQUIRED) 
set(LIBDIR "${PROJECT_SOURCE_DIR}") 


set(HEADERS "${LIBDIR}/map_printer.hpp") 
set(SOURCES "${LIBDIR}/map_printer.cpp") 

add_library("mylib" "${SOURCES}") 

target_include_directories("mylib" PUBLIC "${LIBDIR}" 
              "${Boost_INCLUDE_DIR}" 
              "${mylib_INCLUDE_DIRS}") 
target_link_libraries("mylib" "${Boost_LIBRARIES}" "${mylib_LIBRARIES}") 

install(TARGETS "mylib" ARCHIVE DESTINATION "lib") 
install(FILES ${HEADERS} DESTINATION "include") 

應用/的CMakeLists.txt

cmake_minimum_required(VERSION 3.8.0) 
project(mylib CXX) 

set(APPDIR "${PROJECT_SOURCE_DIR}") 
set(LIBDIR "${APPDIR}/../lib") 

set(SOURCES "${APPDIR}/main.cpp") 

add_subdirectory("${LIBDIR}" "build") 
list(APPEND LIBS "mylib") 

add_executable("myapp" "${SOURCES}") 

target_include_directories("myapp" PUBLIC "${LIBDIR}") 
target_link_libraries("myapp" "${LIBS}") 

install(TARGETS "myapp" DESTINATION "bin") 

要得到一個工作的例子,這裏是一些源文件,在libssl拉在lib(但這個樂趣ction沒有在應用程序中使用) - 我把它們放在學家,因爲他們只是爲了保持完整性,我不想弄亂問題文本:

的問題是,當我cmake app,然後做make VERBOSE=1,產生鏈接器命令是:

/usr/lib/hardening-wrapper/bin/c++  CMakeFiles/myapp.dir/main.cpp.o -o myapp build/libmylib.a -lssl 

但我沒有在app的任何地方指定-lssl。通常情況下,這樣會很好,但是在我的實際應用中,-lssl和其他幾個不必要的符號由於間接依賴性而被包含爲.so文件。當我手動從鏈接器命令中刪除它們時,任務生成並運行得很好。理想情況下,我會使用其.pc文件(本例中未生成)來構建.a,並且如果必須拉入過多依賴關係,則可以手動調整鏈接行,但使用此方法時,鏈接器標記(可能其他的東西)以某種我不明白的方式從lib範圍泄漏出來。

+1

查看['target_link_libraries']的文檔(https://cmake.org/cmake/help/latest/command/target_link_libraries.html);如果您不希望目標的依賴關係傳播,則需要將它們指定爲「PRIVATE」或「PUBLIC」以外的值,默認情況下會按照您使用的那樣進行指定。 – legalize

+0

@legalize Aaaaah!這非常明確,謝謝!如果你想做出答案,那麼它就像任何答案一樣好。 – Paul

回答

0

鏈接是關於解析符號,以便最終目標(獨立的可執行文件或共享對象)具有它需要啓動的所有內容。事情很簡單,當你只依賴單一的圖書館,或者只依賴於其他圖書館的一系列圖書館。任何中等規模或更大規模的項目都不太可能出現這種情況。根本問題是如何處理傳遞依賴關係,例如程序直接使用的東西的依賴關係。

CMake理解所有這一切,旨在讓您在不​​理解整個依賴關係圖的情況下使用庫變得簡單。如果您查看target_link_libraries的文檔,您會看到描述的PRIVATEPUBLICINTERFACE關鍵字。這使您可以描述構建庫時需要的庫的私有需求(編譯定義,編譯參數,從屬庫等)。公共部分允許您指定庫及其依賴者(消費者)需要的東西。界面部分讓你指定依賴者需要的東西,而不是庫本身。命令target_compile_definitionstarget_include_directories的操作類似。

所有這些的結果是,通過在CMake中正確聲明的依賴關係,該依賴關係的客戶端只需將其添加到其自己的target_link_libraries命令中的依賴關係列表中,並自然地獲取所有編譯定義,包括目錄和爲成功編譯和鏈接所必需的暫時鏈接依賴性。

CppCon 2017演示文稿Modern CMake for modular design更詳細地介紹了這一點。