2013-01-07 18 views
18

Buduję w bibliotece cmake, w zależności od wielu innych statycznych bibliotek, bibliotekę o stałej wartości . Chciałbym, aby wszystkie zostały uwzględnione w wyjściowym pliku .lib/.a, więc mogę po prostu wysłać duży plik lib do klientów. W VS2010 istnieje opcja "Link Library Dependencies", która robi dokładnie to.cmake: uwzględnianie zależności bibliotek w statycznej bibliotece lib

Ale nie mogę znaleźć, jak to zrobić w cmake. Czy możesz ustawić tę flagę za pomocą cmake, lub uzyskać ten sam wynik w inny sposób? Próbowałem target_link_libraries (...), a także add_dependencies (...) ale cmake wydaje się po prostu zignorować tę linię dla statycznych bibliotek

+0

Czy masz statyczne wersje bibliotek, z którymi chcesz się połączyć? A może masz tylko wspólne wersje? – tpg2114

+0

Mam wersje statyczne – Rolle

+0

Więc kiedy mówisz, że nie uwzględnia ich w statycznym, czy próbuje połączyć swoją bibliotekę statyczną z innymi bibliotekami współdzielonymi? – tpg2114

Odpowiedz

12

OK, więc mam rozwiązanie. Po pierwsze ważne jest, aby rozpoznać, że biblioteki statyczne nie łączą innych kodów statycznych z kodem. Musi zostać utworzona biblioteka złożona, która w systemie Linux może być wykonana pod numerem ar. Aby uzyskać więcej informacji, patrz Linking static libraries to other static libraries.

Rozważmy dwa pliki źródłowe:

test1.c:

int hi() 
{ 
    return 0; 
} 

test2.c:

int bye() 
{ 
    return 1; 
} 

CMakeLists.txt stworzyć dwie biblioteki, a następnie utworzyć połączony biblioteka wygląda następująco:

projekt (test)

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

Opcje dla polecenia ar są w tym przypadku zależne od platformy, chociaż zmienna CMAKE_AR jest niezależna od platformy. Sprawdzę, czy istnieje bardziej ogólny sposób, aby to zrobić, ale to podejście będzie działać na systemach, które używają ar.


Edit:

podstawie How to set the options for CMAKE_AR wygląda na to lepszy sposób to zrobić byłoby:

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

ten powinien być niezależny od platformy, ponieważ jest to struktura dowodzenia używany tworzyć archiwa wewnętrznie przez CMake. Pod warunkiem, że jedynymi opcjami, które chcesz przekazać do swojego polecenia archiwizacji, są rc, ponieważ są one podłączone do CMake'a dla polecenia ar.

+3

Dzięki, odpowiedni sposób, aby to zrobić w systemie Windows, to dodać niestandardowe polecenie "lib.exe /OUT:combined.lib 1.lib 2.lib " – Rolle

+0

Po użyciu tego przez chwilę, zauważyłem, że polecenie" ar "jest bardzo pobieżne i tworzy połączone biblioteki, które nie działają w co najmniej niektórych wersjach gcc. Myślę, że lepiej po prostu nie próbować łączyć statycznie w ten sposób. – Rolle

+0

Dla mnie działa tylko polecenie add_custom_target opisane powyżej. –

3

Chciałbym udoskonalić inne rozwiązania, udostępniając mój plik CMakeLists.txt, który działa również pod względem zależności między budynkami.

Rozwiązanie nadużywania 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} 
) 

pamiętać, że to rozwiązanie działa tak daleko z Visual Studio, ale myślę, że może to być zgodny wieloplatformowy.Mogę sobie wyobrazić, że po wersji może pracować na platformach 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..." 
) 

Zauważ, że te rozwiązania jakoś Nadużywanie CMake gdyż narzekają cel typu gospodarczy (zamiast statycznych lub dzielone) Jeśli umieścisz target_link_libraries połączenie po zgłoszeniu add_custom_target.

CUpewnij target-deklaracja zgodny rozwiązanie

Żeby było zgodne CUpewnij można zastąpić `połączenia target_link_libraries' przez

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

w moim przypadku to nie jest w pełni zadowalające, ponieważ mainexec ma aby wiedzieć o combinedLib, chociaż oczekuje, że wszystkie zależności będą obsługiwane przez wywołanie target_link_libraries.

Alternatywne rozwiązanie z mniejszym sprzęgłem

Patrząc nieco dalej w kierunku importowanych celów I w końcu znalazłem rozwiązanie, które rozwiązuje mój ostatni problem:

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) 

Jeśli zamierzasz zmodularyzowanie cały dodać GLOBAL po STATIC IMPORTED, aby importowany cel był widoczny na całym świecie.

przenośne rozwiązanie CUpewnij

Przy obecnych wersjach CUpewnij CUpewnij zapewnia pełne wsparcie dla bibliotek zależności przechodnich i interfejsów. Biblioteka interfejsów może następnie "połączyć" się z innymi bibliotekami, a ta biblioteka interfejsów może być z kolei "połączona". Dlaczego znaki cudzysłowu? Chociaż działa to dobrze, to faktycznie nie tworzy fizycznej, połączonej biblioteki, ale raczej tworzy rodzaj aliasu do zestawu "pod-bibliotek". Nadal było to rozwiązanie, które w końcu potrzebowaliśmy, dlatego chciałem dodać to tutaj.

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

target_link_libraries(mainexec combinedLib) 

To wszystko!

Powiązane problemy