Bibliotheken finden und bauen

Ein wichtiger Punkt im Umgang mit C und C++ Projekten aber auch in anderen Sprachen ist das finden von Bibliotheken und deren Header-Dateien im System. So könnten wir bspw. eine Bibliothek installier haben, gegen die wir unser Programm nun linken möchten. Diese Bibliothek im System zu finden gelingt in normalen GNU-Makefiles oftmals mit pkg-file; CMake hat einen eingebauten Befehl: find_library.

Wollen wir bspw. in unsere Hello-World Anwendung eine Routine einbauen, die JSON-parsing mithilfe von json-c übernimmt, brauchen wir die libjson-c-Bibliothek und deren Header-Dateien. Oftmals werden die Header automatisch vom Compiler gefunden, wenn sie bei der Installation im richtigen Ordner abgelegt werden, aber der Linker braucht genaue Informationen darüber, gegen welche Bibliotheken ein Programm gebaut werden soll.

Eine Bibliothek im System finden

Also finden wir die json-c Bibliothek:

find_library(JSONC_LIB NAMES json-c)
if(NOT JSONC_LIB)
message(FATAL_ERROR "Please download and install libjson-c")
endif()

Dieser Befehl sucht auf dem System nach der json-c Bilbiothek und speichert die entsprechenden Informationen in der Variable JSONC_LIB. Ist diese Variable nicht gesetzt, wurde die Variable nicht gefunden. Nun können wir uns überlegen, was dann geschehen soll, bspw. kann der Übersetzungsvorgang abbrechen, mit dem Hinweis darauf, dass json-c nachinstalliert werden muss, oder aber wir übersetzen unsere Anwendung ohne Unterstützung für JSON-Dateien, falls das möglich ist.

Weitere Informationen zu find_library könnnen im CMake Handbuch gefunden werden.

Um unsere Anwendung nun gegen die Library zu bauen, müssen wir CMake das noch mitteilen. Dazu teilen wir CMake erst mit, dass wir ein Programm bauen wollen, und danach fügen wir die Information über die Libraries hinzu.

add_executable(hello_world ${SRC_FILES})
target_link_libraries(hello_world ${JSONC_LIB})

Eine eigene Bibliothek bauen

Neben fertigen Anwendungen kann CMake auch Bibliotheken, also Sammlungen von Funktionen, bauen. Hier ist Vorgehen analog zu dem von Executable, nur geben wir hier den Befehl add_library ein, und geben an, welche Art von Bibliothek (also dynamisch (SHARED) oder statisch (STATIC) gelinkt) wir haben wollen.

add_library(hello SHARED "common.c")

Wir erhalten auf Linux eine libhello.so. Wichtig ist hier, dass sich die Namen nicht doppeln dürfen, also zwei identisch benannte Libraries oder Programme können nicht in einer CMakeLists.txt gebaut werden.

Headerdateien

Größere Projekte, insbesondere Bibliotheken trennen oftmals ihren Code von den Header-Dateien; häufig auch die öffentlichen Header-Dateien von den internen. So sollen Informationen und Variablen versteckt werden, auf die ein Benutzer der Library keinen Zugriff haben soll. Auch wir können Projekte erstellen, in denen bspw. die öffentlichen Header in include/ liegen, ein paar Bibliotheksdateien in lib/ und alle Dateien für das Bauen unserer eigentlichen Anwendung in 'src/' zusammen mit den internen Header-Dateien.

Nun müssen wir CMake noch mitteilen, wo unsere Header-Dateien liegen, damit auch unser eigener Code die öffentlichen Header verwenden kann, bspw. um die richtigen Typdefinitionen zu verwenden. Das geht mit target_include_directories:

target_include_directories(hello PUBLIC include/)

So sagen wir CMake, dass es beim Bauen der Library libhello.so die Header in include/ zur Verfügung stellen soll.

Gebautes Installieren

Oftmals soll es im resultierenden Makefile auch die Möglichkeit geben, die gebauten Dateien zu installieren, also die Bibliotheken an den richtigen Ort zu legen, und die gebauten Programme auffindbar zu machen. Der install-Befehl ermöglicht es uns, diese Direktiven zu geben:

file(GLOB_RECURSE INCLUDE_FILES "include/*.h")
set_target_properties(hello
    PROPERTIES PUBLIC_HEADER "${INCLUDE_FILES}"
)
 
install(TARGETS hello_world hello)

In diesem Beispiel geschieht noch etwas mehr:

  1. wir suchen uns alle öffentlichen Headerdateien in include/ raus
  2. setzen die als PUBLIC_HEADER für unsere Library libhello.so
  3. nennen CMake unser Programm hello_world und die Library libhello.so als zu installieren

install erlaubt auch das Setzen von Installationspfaden für Libraries, Programmdateien und Anderes, weitere Informationen zum install Kommando sind im CMake-Handbuch einzusehen.