2013-07-07 16 views
56

Napisałem bibliotekę, której używałem do kompilacji przy użyciu samodzielnie napisanego Makefile, ale teraz chcę przełączyć na cmake. Drzewo wygląda następująco (usunąłem wszystkie pliki bez znaczenia):Jak utworzyć wspólną bibliotekę za pomocą cmake?

. 
├── include 
│   ├── animation.h 
│   ├── buffers.h 
│   ├── ... 
│   ├── vertex.h 
│   └── world.h 
└── src 
    ├── animation.cpp 
    ├── buffers.cpp 
    ├── ... 
    ├── vertex.cpp 
    └── world.cpp 

Więc co próbuję zrobić, to po prostu skompilować źródła do udostępnionej biblioteki, a następnie zainstalować go z plikami cel.

Większość przykładów znalazłem kompilować pliki wykonywalne z niektórymi bibliotekami współdzielonymi, ale nigdy zwykłą biblioteką współdzieloną. Przydałoby się też, gdyby ktoś mógł po prostu powiedzieć mi bardzo prostą bibliotekę, która używa cmake, więc mogę to wykorzystać jako przykład.

+0

związane http://stackoverflow.com/questions/2152077/is-it-possible-to-get-cmake-to-build-both-a -static-and-shared-of-the-sam –

Odpowiedz

28

Zawsze specifiy minimalną wymaganą wersję cmake

cmake_minimum_required(VERSION 3.9) 

Powinieneś zadeklaruj projekt. cmake mówi, że jest obowiązkowa i będzie definiować zmienne PROJECT_NAME dogodne, PROJECT_VERSION i PROJECT_DESCRIPTION (ta ostatnia zmienna wymagać CUpewnij 3.9):

project(mylib VERSION 1.0.1 DESCRIPTION "mylib description") 

stwierdzenie nowy cel biblioteki. Należy unikać korzystania z file(GLOB ...). Ta funkcja nie zapewnia odpowiedniego opanowania procesu kompilacji. Jeśli jesteś leniwy, copy-paste wyjście ls -1 sources/*.cpp:

add_library(mylib SHARED 
    sources/animation.cpp 
    sources/buffers.cpp 
    [...] 
) 

Ustaw VERSION nieruchomości (opcjonalne, ale jest dobrą praktyką):

set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION}) 

Można również ustawić SOVERSION do poważnej liczby VERSION. Tak więc libmylib.so.1 będzie dowiązaniem symbolicznym do libmylib.so.1.0.0.

set_target_properties(mylib PROPERTIES SOVERSION 1) 

Deklaracja publicznego interfejsu API biblioteki. Ten interfejs API zostanie zainstalowany na potrzeby aplikacji innych firm. Dobrą praktyką jest izolowanie go w drzewie projektu (np. Umieszczanie go w katalogu include/). Zauważ, że prywatne nagłówki nie powinny być instalowane i zdecydowanie sugeruję umieszczenie ich w plikach źródłowych.

set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/mylib.h) 

Jeśli pracujesz z podkatalogów, to nie jest bardzo wygodne, aby zawierać ścieżkę względną jak "../include/mylib.h".Tak, przechodzą w górną katalogu włączonych katalogach:

target_include_directories(mylib PRIVATE .) 

lub

target_include_directories(mylib PRIVATE include) 
target_include_directories(mylib PRIVATE src) 

Tworzenie zainstalować regułę dla biblioteki. Proponuję używać zmiennych CMAKE_INSTALL_*DIR zdefiniowane w GNUInstallDirs:

include(GNUInstallDirs) 

i zadeklarować plików zainstalować:

install(TARGETS mylib 
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 
    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 

Można również wyeksportować plik pkg-config. Ten plików umożliwia aplikacja firmami, aby łatwo importować bibliotekę:

Utwórz plik szablonu pod nazwą mylib.pc.in:

[email protected][email protected] 
[email protected][email protected] 
libdir=${exec_prefix}/@[email protected] 
includedir=${prefix}/@[email protected] 

Name: @[email protected] 
Description: @[email protected] 
Version: @[email protected] 

Requires: 
Libs: -L${libdir} -lmylib 
Cflags: -I${includedir} 

W swojej CMakeLists.txt, dodać regułę, aby rozwinąć @ makr (@ONLY poprosić CMake nie rozszerzać zmienne postaci ${VAR}):

configure_file(mylib.pc.in mylib.pc @ONLY) 

i wreszcie zainstalować wygenerowany plik:

install(FILES ${CMAKE_BINARY_DIR}/mylib.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) 

Użytkownik może również użyj cmake EXPORT feature. Jednak ta funkcja jest kompatybilna tylko z cmake i trudno mi z niej korzystać.

Wreszcie cała CMakeLists.txt powinien wyglądać tak:

cmake_minimum_required(VERSION 3.9) 
project(mylib VERSION 1.0.1 DESCRIPTION "mylib description") 
include(GNUInstallDirs) 
add_library(mylib SHARED src/mylib.c) 
set_target_properties(mylib PROPERTIES 
    VERSION ${PROJECT_VERSION} 
    SOVERSION 1 
    PUBLIC_HEADER api/mylib.h) 
configure_file(mylib.pc.in mylib.pc @ONLY) 
target_include_directories(mylib PRIVATE .) 
install(TARGETS mylib 
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 
    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 
install(FILES ${CMAKE_BINARY_DIR}/mylib.pc 
    DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) 
+2

Tylko uzupełniając niesamowite wyjaśnienie @ Jezza: po wszystkich powyższych krokach programista może zbudować i zainstalować bibliotekę za pomocą 'mkdir build && cd build/&& cmake .. && sudo make install' (lub' sudo make install/strip' do zainstalowania wersja z biblioteką _striped_). – silvioprog

64

Ten minimalny plik CMakeLists.txt kompiluje prosty biblioteki współdzielonej:

cmake_minimum_required(VERSION 2.8) 

project (test) 
set(CMAKE_BUILD_TYPE Release) 

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) 
add_library(test SHARED src/test.cpp) 

Jednak nie mam doświadczenia Kopiowanie plików do innego miejsca docelowego za pomocą CMake. Polecenie file z sygnaturą COPY/INSTALL wygląda na użyteczne.

+14

CMAKE_BUILD_TYPE powinno zostać pominięte, więc decyzja należy do tego, kto się kompiluje. – ManuelSchneid3r

+0

Czy określenie '$ {CMAKE_CURRENT_SOURCE_DIR} /' w katalogu 'katalog_włączeń' jest przydatne? – Jezz

15

Próbuję dowiedzieć się, jak to zrobić sam, i wydaje się, można zainstalować bibliotekę tak:

cmake_minimum_required(VERSION 2.4.0) 

project(mycustomlib) 

# Find source files 
file(GLOB SOURCES src/*.cpp) 

# Include header files 
include_directories(include) 

# Create shared library 
add_library(${PROJECT_NAME} SHARED ${SOURCES}) 

# Install library 
install(TARGETS ${PROJECT_NAME} DESTINATION lib/${PROJECT_NAME}) 

# Install library headers 
file(GLOB HEADERS include/*.h) 
install(FILES ${HEADERS} DESTINATION include/${PROJECT_NAME}) 
Powiązane problemy