2013-01-07 29 views
18

Tôi đang tạo một static lib trong cmake, phụ thuộc vào nhiều lib tĩnh khác. Tôi muốn tất cả chúng được bao gồm trong tập tin đầu ra .lib/.a, vì vậy tôi chỉ có thể gửi một tập tin lib lớn cho khách hàng. Trong VS2010 có một tùy chọn "Liên kết phụ thuộc thư viện" mà thực hiện chính xác điều này.cmake: bao gồm các phụ thuộc thư viện trong static lib

Nhưng tôi không thể tìm cách làm điều đó trong cmake. Bạn có thể thiết lập cờ này thông qua cmake, hoặc có được kết quả tương tự một số cách khác không? Tôi đã thử target_link_libraries (...) và cũng add_dependencies (...) nhưng cmake dường như chỉ đơn giản là bỏ qua dòng này cho libs tĩnh

+0

Bạn có phiên bản tĩnh của thư viện cần được liên kết không? Hay bạn chỉ có phiên bản dùng chung? – tpg2114

+0

tôi có phiên bản tĩnh – Rolle

+0

Vì vậy, khi bạn nói nó không bao gồm chúng trong tĩnh của bạn, là nó cố gắng liên kết thư viện tĩnh của bạn với các thư viện được chia sẻ khác? – tpg2114

Trả lời

12

Được rồi, vì vậy tôi có một giải pháp. Trước tiên, điều quan trọng là phải nhận ra rằng các thư viện tĩnh không liên kết các thư viện tĩnh khác với mã. Một thư viện kết hợp phải được tạo, mà trên linux có thể được thực hiện với ar. Xem Linking static libraries to other static libraries để biết thêm thông tin tại đó.

Hãy xem xét hai file nguồn:

test1.c:

int hi() 
{ 
    return 0; 
} 

test2.c:

int bye() 
{ 
    return 1; 
} 

Các CMakeLists.txt để tạo ra hai thư viện và sau đó tạo ra một thư viện kết hợp trông giống như:

dự án (thử nghiệm)

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>) 

Tùy chọn cho lệnh ar phụ thuộc vào nền tảng trong trường hợp này, mặc dù biến số CMAKE_AR là nền tảng độc lập. Tôi sẽ poke xung quanh để xem nếu có một cách tổng quát hơn để làm điều này, nhưng cách tiếp cận này sẽ làm việc trên các hệ thống sử dụng ar.


Edit:

Dựa trên How to set the options for CMAKE_AR nó trông giống như những cách tốt hơn để làm điều này sẽ là:

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

này nên nền tảng độc lập vì đây là cấu trúc lệnh sử dụng để tạo lưu trữ nội bộ bởi CMake. Cung cấp tất nhiên các tùy chọn duy nhất bạn muốn chuyển đến lệnh lưu trữ của bạn là rc vì chúng được hardwired vào CMake cho lệnh ar.

+3

Cảm ơn, cách tương ứng để thực hiện trên Windows là thêm lệnh tùy chỉnh "lib.exe /OUT:combined.lib 1.lib 2.lib " – Rolle

+0

Sau khi sử dụng điều này một chút, tôi đã nhận thấy lệnh" ar "rất sơ sài và tạo ra các libs kết hợp không hoạt động trong ít nhất một số phiên bản của gcc. Tôi nghĩ rằng chúng tôi chỉ tốt hơn là không cố gắng liên kết tĩnh theo cách này. – Rolle

+0

Đối với tôi chỉ lệnh add_custom_target như được mô tả trước tiên. –

3

Tôi muốn nâng cao các giải pháp khác bằng cách cung cấp tệp CMakeLists.txt thực sự hoạt động cũng trong điều kiện xây dựng các phụ thuộc.

Giải pháp lạm dụng 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} 
) 

Lưu ý rằng giải pháp này hoạt động rất xa với Visual Studio nhưng tôi đoán nó có thể được thực hiện đa nền tảng phù hợp.Tôi có thể tưởng tượng rằng các phiên bản sau có thể làm việc cho các nền tảng Unix-based:

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..." 
) 

Lưu ý rằng các giải pháp này bằng cách nào đó lạm dụng CMake vì nó sẽ phàn nàn về một mục tiêu của loại UTILITY (thay vì tĩnh hoặc chia sẻ) nếu bạn đặt target_link_libraries gọi sau tuyên bố add_custom_target.

CMake mục tiêu khai tuân thủ giải pháp

Để làm cho nó CMake phù hợp, bạn có thể thay thế 'gọi target_link_libraries' bởi

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

Trong trường hợp của tôi nó không phải là hoàn toàn thỏa đáng vì mainexec có để biết về combinedLib mặc dù nó dự kiến ​​tất cả các phụ thuộc sẽ được xử lý bằng cuộc gọi target_link_libraries.

giải pháp thay thế với ít khớp nối

Nhìn một chút nữa về phía mục tiêu nhập khẩu Tôi cuối cùng đã tìm thấy một giải pháp mà giải quyết vấn đề cuối cùng của tôi:

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) 

Nếu bạn có ý định để modularize toàn bộ thêm GLOBAL sau STATIC IMPORTED để làm cho mục tiêu được nhập trên toàn cầu hiển thị.

di động giải pháp CMake

Với các phiên bản CMake hiện CMake cung cấp hỗ trợ đầy đủ cho phụ thuộc bắc cầu và các thư viện giao diện. Sau đó, một thư viện giao diện có thể "liên kết" với các thư viện khác và thư viện giao diện này có thể bị "liên kết". Tại sao dấu ngoặc kép? Trong khi điều này hoạt động tốt, điều này thực sự không tạo ra một thư viện vật lý, kết hợp mà là tạo ra một loại bí danh cho tập hợp các "thư mục con". Tuy nhiên, đây là giải pháp mà chúng tôi cần cuối cùng, đó là lý do tại sao tôi muốn thêm nó vào đây.

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

target_link_libraries(mainexec combinedLib) 

Vậy đó!

Các vấn đề liên quan