Wszystko to z tego samego źródła, po prostu chcę mieć wersję statyczną i współdzieloną. Proste do zrobienia?
Tak, jest to umiarkowanie łatwe. Wystarczy użyć dwóch poleceń „add_library”:
add_library(MyLib SHARED source1.c source2.c)
add_library(MyLibStatic STATIC source1.c source2.c)
Nawet jeśli masz wiele plików źródłowych, umieścisz listę źródeł w zmiennej cmake, więc nadal jest to łatwe.
W systemie Windows prawdopodobnie powinieneś nadać każdej bibliotece inną nazwę, ponieważ istnieje plik „.lib” zarówno dla współdzielonej, jak i statycznej. Ale w systemie Linux i Mac możesz nawet nadać obu bibliotekom tę samą nazwę (np. libMyLib.a
I libMyLib.so
):
set_target_properties(MyLibStatic PROPERTIES OUTPUT_NAME MyLib)
Ale nie polecam nadawania tej samej nazwy statycznej i dynamicznej wersji biblioteki. Wolę używać różnych nazw, ponieważ ułatwia to wybór łączenia statycznego i dynamicznego w wierszu kompilacji dla narzędzi, które prowadzą do biblioteki. Zwykle wybieram nazwy takie jak libMyLib.so
(udostępnione) i libMyLib_static.a
(statyczne). (To byłyby nazwy w systemie Linux.)
-fPIC
), co dodaje niewielką ilość narzutu czasu wykonania, gdy te biblioteki statyczne są używane. Tak więc dla maksymalnej wydajności ta odpowiedź jest nadal najlepsza.Od wersji 2.8.8 CMake można używać „bibliotek obiektów”, aby uniknąć powielania kompilacji plików obiektowych . Na przykładzie biblioteki Christophera Brunsa z dwoma plikami źródłowymi:
Z dokumentacji CMake :
Mówiąc najprościej,
add_library(objlib OBJECT ${libsrc})
polecenie instruuje CMake, aby skompilował pliki źródłowe do*.o
plików obiektowych. Ta kolekcja*.o
plików jest następnie określana tak, jak$<TARGET_OBJECT:objlib>
w dwóchadd_library(...)
poleceniach, które wywołują odpowiednie polecenia tworzenia bibliotek, które budują biblioteki współużytkowane i biblioteki statyczne z tego samego zestawu plików obiektowych. Jeśli masz dużo plików źródłowych, kompilacja*.o
plików może zająć dość dużo czasu; w przypadku bibliotek obiektów kompilujesz je tylko raz.Cena, jaką płacisz, jest taka, że pliki obiektowe muszą być zbudowane jako kod niezależny od pozycji, ponieważ biblioteki współdzielone tego potrzebują (biblioteki statyczne nie dbają o to). Zwróć uwagę, że kod niezależny od pozycji może być mniej wydajny, więc jeśli dążysz do maksymalnej wydajności, wybierz biblioteki statyczne. Ponadto łatwiej jest dystrybuować statycznie połączone pliki wykonywalne.
źródło
target_link_libraries()
wywołania zależne od Twojej biblioteki nie mogły używać „biblioteki obiektów” do łączenia się; muszą one być przeznaczone dla nowych bibliotek współdzielonych lub statycznych (i mogą zostać zduplikowane). Ale w przeciwieństwie do doświadczeń pierwszych komentatorów było to całkiem przydatne i pozwoliło mi usunąć wszystkie zduplikowane cele i wyciąć wszystkie mojeCMakeLists.txt
pliki prawie o połowę.set_property
działał tylko wtedy, gdy korzystałem,objlib
a nie podczas używania${objlib}
. Może więc tę odpowiedź można poprawić?Generalnie nie ma potrzeby dublowania
ADD_LIBRARY
połączeń w swoim celu. Po prostu skorzystaj zbudując najpierw (w jednym out-of-źródła katalogu) z
-DBUILD_SHARED_LIBS:BOOL=ON
, izOFF
w drugiej.źródło
Możliwe jest spakowanie wszystkiego w tym samym oddechu kompilacji, jak sugerowały poprzednie odpowiedzi, ale odradzałbym to, ponieważ w końcu to hack, który działa tylko w prostych projektach. Na przykład, w pewnym momencie możesz potrzebować różnych flag dla różnych wersji biblioteki (szczególnie w systemie Windows, gdzie flagi są zwykle używane do przełączania się między eksportowanymi symbolami lub nie). Lub, jak wspomniano powyżej, możesz chcieć umieścić
.lib
pliki w różnych katalogach w zależności od tego, czy odpowiadają one bibliotekom statycznym, czy współdzielonym. Każda z tych przeszkód będzie wymagała nowego hakowania.To może być oczywiste, ale jedną z alternatyw, o których wcześniej nie wspominano, jest uczynienie typu biblioteki parametrem:
Posiadanie udostępnionej i statycznej wersji biblioteki w dwóch różnych drzewach binarnych ułatwia obsługę różnych opcji kompilacji. Nie widzę żadnych poważnych wad w utrzymywaniu odrębności drzew kompilacji, zwłaszcza jeśli kompilacje są zautomatyzowane.
Zauważ, że nawet jeśli zamierzasz mutualizować kompilacje przy użyciu
OBJECT
biblioteki pośredniej (z zastrzeżeniami wymienionymi powyżej, więc potrzebujesz do tego ważnego powodu), nadal możesz umieścić biblioteki końcowe w dwóch różnych projektach.źródło
To rzeczywiście możliwe. Jak powiedział @Christopher Bruns w swojej odpowiedzi, musisz dodać dwie wersje biblioteki:
Następnie, jak opisano tutaj , musisz określić, że oba cele powinny używać tej samej nazwy wyjściowej i nie nadpisywać swoich plików:
W ten sposób otrzymasz libmylib.a i libmylib.so (w systemie Linux) lub mylib.lib i mylib.dll (w systemie Windows).
źródło