wake-up-neo.com

Wie erstelle ich eine gemeinsame Bibliothek mit cmake?

Ich habe eine Bibliothek geschrieben, die ich mit einem selbst geschriebenen Makefile kompiliert habe, aber jetzt möchte ich zu cmake wechseln. Der Baum sieht so aus (ich habe alle irrelevanten Dateien entfernt):

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

Ich versuche also nur, die Quelle in eine gemeinsam genutzte Bibliothek zu kompilieren und sie dann mit den Header-Dateien zu installieren.

Die meisten Beispiele, die ich gefunden habe, kompilieren ausführbare Dateien mit einigen gemeinsam genutzten Bibliotheken, aber niemals nur mit einer einfach gemeinsam genutzten Bibliothek. Es wäre auch hilfreich, wenn mir jemand eine sehr einfache Bibliothek mitteilen könnte, die cmake verwendet, damit ich dies als Beispiel verwenden kann.

110
Florian M

Geben Sie immer die mindestens erforderliche Version von cmake an.

cmake_minimum_required(VERSION 3.9)

Sie sollten ein Projekt deklarieren. cmake sagt, dass es obligatorisch ist und bequeme Variablen PROJECT_NAME, PROJECT_VERSION und PROJECT_DESCRIPTION definiert (diese letztere Variable erfordert cmake 3.9):

project(mylib VERSION 1.0.1 DESCRIPTION "mylib description")

Deklarieren Sie ein neues Bibliotheksziel. Bitte vermeiden Sie die Verwendung von file(GLOB ...). Diese Funktion bietet keine begleitete Beherrschung des Kompilierungsprozesses. Wenn Sie faul sind, kopieren Sie die Ausgabe von ls -1 sources/*.cpp:

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

Setze VERSION Eigenschaft (optional, aber es ist eine gute Übung):

set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION})

Sie können SOVERSION auch auf die Hauptzahl von VERSION setzen. Also ist libmylib.so.1 Ein Symlink zu libmylib.so.1.0.0.

set_target_properties(mylib PROPERTIES SOVERSION 1)

Deklarieren Sie die öffentliche API Ihrer Bibliothek. Diese API wird für Anwendungen von Drittanbietern installiert. Es wird empfohlen, es in Ihrem Projektbaum zu isolieren (z. B. das Verzeichnis include/). Beachten Sie, dass private Header nicht installiert werden sollten, und ich empfehle dringend, sie zusammen mit den Quelldateien zu platzieren.

set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/mylib.h)

Wenn Sie mit Unterverzeichnissen arbeiten, ist es nicht sehr praktisch, einen relativen Pfad wie "../include/mylib.h" Einzufügen. Übergeben Sie also das oberste Verzeichnis in den enthaltenen Verzeichnissen:

target_include_directories(mylib PRIVATE .)

oder

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

Erstellen Sie eine Installationsregel für Ihre Bibliothek. Ich empfehle die Verwendung von Variablen CMAKE_INSTALL_*DIR, Die in GNUInstallDirs definiert sind:

include(GNUInstallDirs)

Und deklarieren Sie die zu installierenden Dateien:

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

Sie können auch eine pkg-config - Datei exportieren. Mit dieser Datei können Drittanbieteranwendungen Ihre Bibliothek problemlos importieren:

Erstellen Sie eine Vorlagendatei mit dem Namen mylib.pc.in (Weitere Informationen finden Sie unter pc (5) manpage ):

[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}

Fügen Sie in Ihrem CMakeLists.txt Eine Regel zum Erweitern von @ - Makros hinzu (@ONLY - Bitten Sie, Variablen der Form ${VAR} Nicht zu erweitern.):

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

Zum Schluss installieren Sie die generierte Datei:

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

Sie können auch cmake EXPORT feature verwenden. Diese Funktion ist jedoch nur mit cmake kompatibel und ich finde es schwierig, sie zu verwenden.

Schließlich sollte das gesamte CMakeLists.txt So aussehen:

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

Diese minimale CMakeLists.txt-Datei kompiliert eine einfache gemeinsam genutzte Bibliothek:

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)

Ich habe jedoch keine Erfahrung damit, Dateien mit CMake an einen anderen Speicherort zu kopieren. Der Dateibefehl mit der Signatur COPY/INSTALL scheint nützlich zu sein.

71
Robert Franke

Ich versuche zu lernen, wie man das selbst macht, und es scheint, dass Sie die Bibliothek folgendermaßen installieren können:

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})
21
gromit190

Erstens ist dies das Verzeichnislayout, das ich verwende:

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

Nach ein paar Tagen ist dies meine Lieblingsmethode, dank modernem 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)

add_library(${PROJECT_NAME} ...)

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)

Nach dem Ausführen von CMake und dem Installieren der Bibliothek ist es nicht erforderlich, Find ***. Cmake-Dateien zu verwenden. Diese können folgendermaßen verwendet werden:

find_package(MyLib REQUIRED)

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

Das ist es, wenn es in einem Standardverzeichnis installiert wurde, wird es gefunden und es besteht keine Notwendigkeit, etwas anderes zu tun. Wenn es in einem nicht standardmäßigen Pfad installiert wurde, ist es auch einfach, CMake mitzuteilen, wo MyLibConfig.cmake zu finden ist:

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

Ich hoffe, das hilft allen so sehr, wie es mir geholfen hat. Alte Methoden waren ziemlich umständlich.

8
Luis