Jak utworzyć bibliotekę współdzieloną za pomocą cmake?

Napisałem bibliotekę, której używałem do kompilacji przy użyciu własnoręcznie napisanego pliku Makefile, ale teraz chcę przełączyć się na cmake. Drzewo wygląda tak (usunąłem wszystkie nieistotne Pliki):

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

Więc to, co próbuję zrobić, to skompilować źródło do udostępnionej biblioteki, a następnie zainstalować je z plikami nagłówkowymi.

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

Author: Jezz, 2013-07-07

4 answers

Zawsze podaj minimalną wymaganą wersję cmake

cmake_minimum_required(VERSION 3.9)

Powinieneś zgłosić projekt. cmake mówi, że jest to obowiązkowe i zdefiniuje wygodne zmienne PROJECT_NAME, PROJECT_VERSION i PROJECT_DESCRIPTION (ta ostatnia zmienna wymaga cmake 3.9):

project(mylib VERSION 1.0.1 DESCRIPTION "mylib description")

Zadeklaruj nowy cel biblioteki. Należy unikać stosowania file(GLOB ...). Funkcja ta nie zapewnia opanowania procesu kompilacji. Jeśli jesteś leniwy, skopiuj i wklej wyjście ls -1 sources/*.cpp:

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

Set VERSION property (opcjonalne, ale jest to dobra praktyka):

set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION})

Można również ustawić {[22] } na numer główny VERSION. Tak więc {[24] } będzie dowiązaniem symbolicznym do libmylib.so.1.0.0.

set_target_properties(mylib PROPERTIES SOVERSION 1)

Zadeklaruj publiczne API swojej biblioteki. Ten API zostanie zainstalowany dla aplikacji innych firm. Dobrą praktyką jest wyizolowanie go w drzewie projektu (np. umieszczenie go w katalogu include/). Zauważ, że prywatne nagłówki nie powinny być instalowane i zdecydowanie sugeruję umieszczenie ich z plikami źródłowymi.

set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/mylib.h)

Jeśli pracujesz z podkatalogach, nie jest zbyt wygodne dołączanie ścieżki względnej, takiej jak "../include/mylib.h". Tak więc, podaj górny katalog w dołączonych katalogach:

target_include_directories(mylib PRIVATE .)

Lub

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

Utwórz regułę instalacji dla swojej biblioteki. Sugeruję użycie zmiennych CMAKE_INSTALL_*DIR zdefiniowanych w GNUInstallDirs:

include(GNUInstallDirs)

I zadeklarować pliki do zainstalowania:

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

Można również wyeksportować plik pkg-config. Pliki te pozwalają aplikacji innej firmy łatwo zaimportować bibliotekę:

Utwórz plik szablonu o nazwie mylib.pc.in (zobacz pc(5) strona Man aby uzyskać więcej informacji):

prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@
libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@

Name: @PROJECT_NAME@
Description: @PROJECT_DESCRIPTION@
Version: @PROJECT_VERSION@

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

W twoim CMakeLists.txt Dodaj regułę, aby rozwinąć @ makra (@ONLY poproś cmake, aby nie rozwijał zmiennych formularza ${VAR}):

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

I na koniec zainstaluj wygenerowany plik:

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

Możesz również użyć cmake EXPORT funkcja . Jednak ta funkcja jest kompatybilna tylko z cmake i uważam, że jest trudna w użyciu.

Wreszcie całość CMakeLists.txt powinna wyglądać następująco:

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)
 75
Author: Jezz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-04 07:13:18

To minimalne Cmakelisty.plik txt kompiluje prostą bibliotekę współdzieloną:

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)

Nie mam jednak doświadczenia w kopiowaniu plików do innego miejsca docelowego za pomocą CMake. Polecenie file z podpisem COPY / INSTALL wygląda na przydatne.

 68
Author: Robert Franke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-07 11:22:26

Próbuję się nauczyć jak to zrobić samemu, i wydaje się, że można zainstalować bibliotekę w ten sposób:

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})
 16
Author: gromit190,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-04 14:55:01

Po pierwsze, jest to układ katalogu, którego używam:

.
├── include
│   ├── class1.hpp
│   ├── ...
│   └── class2.hpp
└── src
    ├── class1.cpp
    ├── ...
    └── class2.cpp

Po kilku dniach przyjrzenia się temu, jest to mój ulubiony sposób na zrobienie tego dzięki nowoczesnemu CMake:

cmake_minimum_required(VERSION 3.5)
project(mylib VERSION 1.0.0 LANGUAGES CXX)

set(DEFAULT_BUILD_TYPE "Release")

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
  message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.")
  set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE)
  # Set the possible values of build type for cmake-gui
  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

include(GNUInstallDirs)

set(SOURCE_FILES src/class1.cpp src/class2.cpp)

target_include_directories(${PROJECT_NAME} PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
    PRIVATE src)

set_target_properties(${PROJECT_NAME} PROPERTIES
    VERSION ${PROJECT_VERSION}
    SOVERSION 1)

install(TARGETS ${PROJECT_NAME} EXPORT MyLibConfig
    ARCHIVE  DESTINATION ${CMAKE_INSTALL_LIBDIR}
    LIBRARY  DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME  DESTINATION ${CMAKE_INSTALL_BINDIR})
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})

install(EXPORT MyLibConfig DESTINATION share/MyLib/cmake)

export(TARGETS ${PROJECT_NAME} FILE MyLibConfig.cmake)

Po uruchomieniu CMake i zainstalowaniu biblioteki nie ma potrzeby używania Find***.pliki cmake, można go używać w następujący sposób:

find_package(MyLib REQUIRED)

#No need to perform include_directories(...)
target_link_libraries(${TARGET} mylib)

To jest to, jeśli został zainstalowany w standardowym katalogu to zostanie znaleziony i nie ma potrzeby robić nic innego. Jeśli został zainstalowany w niestandardowa ścieżka, jest również łatwa, po prostu powiedz CMake, gdzie znaleźć MyLibConfig.cmake using:

cmake -DMyLib_DIR=/non/standard/install/path ..

Mam nadzieję, że to pomoże wszystkim tak bardzo, jak pomogło mi. Stare sposoby robienia tego były dość uciążliwe.

 5
Author: Luis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-16 17:27:04