2013-01-07 166 views
18

我在cmake中構建了一個靜態庫,這依賴於許多其他靜態庫。我希望它們都包含在輸出的.lib/.a文件中,這樣我就可以將一個大的lib文件發送給客戶。在VS2010中有一個選項「鏈接庫依賴關係」就是這樣做的。cmake:在靜態庫中包含庫依賴關係

但我無法找到如何在cmake中做到這一點。你可以通過cmake設置這個標誌,或者通過其他方式獲得相同的結果嗎?我已經嘗試過target_link_libraries(...)和add_dependencies(...),但cmake似乎簡單地忽略靜態庫的這一行

+0

你有靜態版本的庫需要鏈接?或者你只有共享版本? – tpg2114

+0

我有靜態版本 – Rolle

+0

因此,當你說它不包括他們在你的靜態,它試圖鏈接你的靜態庫與其他共享庫? – tpg2114

回答

12

好吧,所以我有一個解決方案。首先認識到靜態庫不會將其他靜態庫鏈接到代碼中很重要。必須創建一個組合庫,在Linux上可以通過ar完成。請參閱Linking static libraries to other static libraries瞭解更多信息。

考慮兩個源文件:

test1.c:

int hi() 
{ 
    return 0; 
} 

test2.c中:

int bye() 
{ 
    return 1; 
} 

CMakeLists.txt創建兩個庫,然後創建一個組合庫的樣子:

項目(測試)

add_library(lib1 STATIC test1.c) 
add_library(lib2 STATIC test2.c) 

add_custom_target(combined ALL 
    COMMAND ${CMAKE_AR} rc libcombined.a $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>) 

在這種情況下,ar命令的選項依賴於平臺,但CMAKE_AR變量與平臺無關。我會仔細研究是否有更通用的方法來實現這一點,但這種方法適用於使用ar的系統。


編輯:

基於How to set the options for CMAKE_AR看起來更好的方式來做到這一點是:

add_custom_target(combined ALL 
    COMMAND ${CMAKE_CXX_ARCHIVE_CREATE} libcombined.a $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>) 

這應該是平臺無關的,因爲這是使用的命令結構由CMake在內部創建檔案。當然,你想傳遞給你的歸檔命令的唯一選項是rc,因爲這些命令被硬連接到CMake中以用於ar命令。

+3

謝謝,在Windows上執行它的相應方式是添加一個自定義命令「lib.exe /OUT:combined.lib 1.lib 2.lib「 – Rolle

+0

使用了這一點後,我注意到」ar「命令非常粗略,並且生成了至少在某些版本的gcc中不起作用的組合庫。我認爲我們只是不嘗試以這種方式進行靜態鏈接。 – Rolle

+0

對於我而言,只有第一次描述的add_custom_target命令有效。 –

3

我想通過輸入我的CMakeLists.txt文件,實際工作中也依賴建設方面,以提高其他的解決方案。

解決濫用CMake的

cmake_minimum_required(VERSION 2.8) 

add_library(lib1 test1.cpp) 
add_library(lib2 test2.cpp) 
include_directories(${CMAKE_CURRENT_DIR}) 
add_executable(mainexec main.cpp) 
target_link_libraries(mainexec combinedLib) # Important to place before add_custom_target 

set(LIBNAME "combinedLib.lib") 

add_custom_command(
    OUTPUT ${LIBNAME} 
    COMMAND lib.exe /OUT:${LIBNAME} $<TARGET_FILE:lib1> $<TARGET_FILE:lib2> 
    DEPENDS lib1 lib2 
    COMMENT "Combining libs..." 
) 

add_custom_target(combinedLib 
    DEPENDS ${LIBNAME} 
) 

請注意,此解決方案至今工作與Visual Studio,但我想它可以製成多平臺兼容。我可以想像,以下版本可能會爲基於Unix平臺上工作:

set(LIBNAME "libCombinedLib.a") 

add_custom_command(
    OUTPUT ${LIBNAME} 
    COMMAND ar -rcT ${LIBNAME} $<TARGET_FILE:lib1> $<TARGET_FILE:lib2> 
    DEPENDS lib1 lib2 
    COMMENT "Combining libs..." 
) 

注意,這些解決方案在某種程度上濫用CMake的,因爲它會抱怨型UTILITY(而不是靜態或共享)的目標,如果你放置在add_custom_target聲明後致電target_link_libraries

CMake的目標聲明兼容的解決方案

爲了使CMake的標準,您可以通過

target_link_libraries(mainexec ${LIBNAME}) 
add_dependencies(mainexec combinedLib) 

在我的情況下更換`target_link_libraries'調用它並不完全令人滿意,因爲mainexec有知道combinedLib,雖然它期望所有的依賴由target_link_libraries調用處理。

用更少的耦合替代解決方案

看起來有點進一步向進口的目標,我終於找到了解決我的最後一個問題的解決方案:如果您打算模塊化整個後添加GLOBAL

cmake_minimum_required(VERSION 2.8) 

add_library(lib1 test1.cpp) 
add_library(lib2 test2.cpp) 
include_directories(${CMAKE_CURRENT_DIR}) 
add_executable(mainexec main.cpp) 

set(LIBNAME "combinedLib.lib") 

add_custom_command(
    OUTPUT ${LIBNAME} 
    COMMAND lib.exe /OUT:${LIBNAME} $<TARGET_FILE:lib1> $<TARGET_FILE:lib2> 
    DEPENDS lib1 lib2 
    COMMENT "Combining libs..." 
) 

add_custom_target(combinedLibGenerator 
    DEPENDS ${LIBNAME} 
) 

add_library(combinedLib STATIC IMPORTED) 
set_property(TARGET combinedLib PROPERTY IMPORTED_LOCATION ${LIBNAME}) 
add_dependencies(combinedLib combinedLibGenerator) 

target_link_libraries(mainexec combinedLib) 

STATIC IMPORTED使導入的目標全局可見。

便攜式CMake的解決方案

與當前版本的CMake CMake的爲傳遞依賴和接口庫的完全支持。接口庫可以與其他庫「鏈接」,而這個接口庫又可以被「鏈接」。爲什麼引號?雖然這很好,但這實際上不會創建一個物理的,組合的庫,而是爲這組「子庫」創建一種別名。這仍然是我們最終需要的解決方案,這就是爲什麼我想在這裏添加它。

add_library(combinedLib INTERFACE) 
target_link_libraries(combinedLib INTERFACE lib1 lib2) 

target_link_libraries(mainexec combinedLib) 

就是這樣!