CMAKE – Wie kopiert man die Header-Datei der statischen Bibliothek richtig nach /usr/include?

Lesezeit: 8 Minuten

Benutzeravatar von Miroslav Mares
Miroslav Stuten

Ich steige in die CMAKE-Nutzung mit C ein und erstelle eigentlich zwei sehr kleine statische Bibliotheken.

Mein Ziel ist:

  1. Die Bibliotheken werden kompiliert und in *.a-Dateien gelinkt. [THIS
    WORKS]
  2. Dann möchte ich diese *.a-Dateien nach /usr/local/lib kopieren [THIS ALSO WORKS]
  3. Soweit ich über Bibliotheken weiß (sehr wenig), werden sie mit verknüpft -lnameoflib, was ein Compiler-Flag ist. OK. Ich habe meine CMakeLists.txt vorbereitet und sie kopiert tatsächlich *.a-Dateien hinein /usr/local/lib. Um sie jedoch in einem Programm verwenden zu können, muss ich auch ihre Header-Dateien hinein kopieren /usr/local/includedann kann ich sie ganz einfach einbinden #include <mylibheader.h>. So verstehe ich das jetzt.

Und meine Frage ist: Wie kopiert man Header-Dateien mit CMAKE in den Ordner /usr/include? Ich möchte, dass es sie automatisch kopiert, wenn make install ausgeführt wird, wie es *.a-Dateien sind.

Für beide Bibliotheken habe ich eine ähnliche CMakeLists.txt:

project(programming-network)

add_library(programming-network STATIC
    send_string.c
    recv_line.c
    )

INSTALL(TARGETS programming-network
        DESTINATION "lib"
        )

  • Warum nicht einfach eine Zeile hinzufügen Makefile unter install: \n\tcp $INCLUDES/* /usr/include/ ?

    – Lukas Campbell

    7. Mai 2012 um 18:40 Uhr

  • OK, aber es bedeutet, dass es nicht direkt in CMakeLists.txt gemacht werden kann und dass ich es jedes Mal neu in Makefile schreiben muss, nachdem ich cmake ausgeführt habe?

    – Miroslav Stuten

    7. Mai 2012 um 18:43 Uhr

  • Ich würde davon ausgehen, dass ich mit cmake und CMakeLists.txt nicht allzu vertraut bin, ich bevorzuge die Verwendung von gnu-automake.

    – Lukas Campbell

    7. Mai 2012 um 18:48 Uhr

  • Wenn Ihr Ziel nach dem Aufruf von CMake mit installiert wurde -DCMAKE_INSTALL_PREFIX=/usrdann würde deine lib in landen /usr/lib (Wie erwartet mit dem Präfix auf /usr), aber Ihre Header würden in landen /include (wahrscheinlich nicht erwartet). Pers Antwort macht mehr Sinn.

    – Frazer

    7. Mai 2012 um 22:46 Uhr

  • @lukecampbell Das manuelle Hinzufügen von Zeilen zum Makefile würde den Zweck der Verwendung von cmake zunichte machen (was 100-mal besser ist als automake).

    – Ilia Choly

    18. Dezember 2012 um 16:12 Uhr


Benutzeravatar von flm8620
film8620

Ein besserer Weg für die neueste cmake-Version ist die Verwendung von Zielen PUBLIC_HEADER Eigenschaften.

project(myproject)

add_library(mylib some.c another.c)
set_target_properties(mylib PROPERTIES PUBLIC_HEADER "some.h;another.h")
INSTALL(TARGETS mylib 
        LIBRARY DESTINATION some/libpath
        PUBLIC_HEADER DESTINATION some/includepath
)

Einige Hinweise:

PUBLIC_HEADER

CMake-Installationsbefehl

  • Das war genau das, wonach ich gesucht hatte. Danke für den Beispielcode.

    – m-bitsnbites

    28. November 2016 um 9:58 Uhr

  • @flm8620 Was ist, wenn ich viele Header-Dateien habe? Gibt es eine intelligentere Lösung, als alle in der angegebenen Zeichenfolge aufzulisten set_target_properties?

    – Marco Stramezzi

    31. Oktober 2017 um 11:11 Uhr

  • @MarcoStramezzi Sie können den Befehl file(GLOB ***) in CMake verwenden, um Dateien zu greifen

    – flm8620

    1. November 2017 um 14:48 Uhr

  • @flm8620 Ich glaube, die Autoren von cmake raten aus verschiedenen Gründen von der Verwendung von GLOB ab. Einige sind hier wahrscheinlich nicht anwendbar, da Abhängigkeiten nicht durch die Eigenschaft PUBLIC_HEADER bestimmt werden. Auf jeden Fall war der Beitrag hilfreich und hat mir weitergeholfen.

    – R. Schultz

    8. November 2017 um 23:22 Uhr

  • Dieser Kommentar sollte eine Bearbeitung sein, aber andere glauben, dass er besser als Kommentar geeignet ist. Wenn Sie eine Liste anstelle von verwenden "some.h;another.h", stellen Sie sicher, dass Sie den Variablennamen in Anführungszeichen setzen. Andernfalls führt dies zu einem Fehler oder es wird nur das erste Element in der Liste installiert. Was tatsächlich passiert, hängt von der Anzahl der Elemente in der Liste ab. Zum Beispiel set_target_properties(myproject PROPERTIES PUBLIC_HEADER "${my_header_files}") ist richtig set_target_properties(myproject PROPERTIES PUBLIC_HEADER ${my_header_files}) ist nicht.

    – R. Schultz

    9. November 2017 um 16:39 Uhr


Auf eine viel bessere Weise werden alle Dateien kopiert, die dem Muster entsprechen, und die Verzeichnisstruktur beibehalten.

INSTALL (
    DIRECTORY ${CMAKE_SOURCE_DIR}/include/
    DESTINATION include
    FILES_MATCHING PATTERN "*.h*")

  • Dieser Ansatz funktioniert nicht, wenn das Ziel Abhängigkeiten mit öffentlichen Headern hat. In diesem Fall ist es wahrscheinlich besser, PUBLIC_HEADER aus der akzeptierten Antwort zu verwenden. Es fügt Header rekursiv hinzu (z. B. aus statischen Bibliotheken).

    – Andrej

    16. August 2019 um 1:41 Uhr


  • @Akela thx, im letzten Jahr hat sich das Skript ziemlich verändert, ich werde versuchen, das Projekt mit dem gesamten Skript auf Github zu stellen. Grundsätzlich betrachte ich alle Dateien im Include-Ordner PUBLIC und alle Dateien in src PRIVATE, also mache ich TARGET_INCLUDE_DIRECTORIES (mylib PUBLIC $ $ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src), I erstellte auch zwei Dateien, mylibConfig.cmake und mylibTargets.cmake, die alle ihre Abhängigkeiten enthalten, und installieren Sie sie schließlich mit INSTALL (DIRECTORY include / DESTINATION include COMPONENT development).

    – J.Adler

    17. August 2019 um 1:39 Uhr

  • Hm … Ich denke, es kann das Problem sogar für abhängige Bibliotheken lösen (hängt davon ab, wie mylibTargets.cmake implementiert ist). Wie auch immer, Ihre Antwort ist für die Anfangsfrage vollkommen in Ordnung. In meinem Fall mit zwei Bibliotheken hängt eine von der anderen ab, ich habe auch so etwas wie mylibTargets.cmake hinzugefügt, das den Aufruf find_dependency() enthielt. Ich bin mir nicht sicher, ob es richtig war, aber zumindest hat es bei mir funktioniert.

    – Andrej

    18. August 2019 um 2:18 Uhr

  • Entschuldigung, ich habe es noch einmal überprüft, und es funktioniert mit Bibliotheken. Ich habe keine Ahnung, warum es beim ersten Mal keine Header aus Abhängigkeiten kopiert hat. Bisher ist dies meiner Meinung nach die beste Antwort, da die Verzeichnisstruktur erhalten bleibt.

    – Andrej

    20. August 2019 um 5:43 Uhr

  • @TomášRůžička, ich habe ein Projekt in Github mit einigen cmake-Skripten, es wurde nicht mit Blick auf mehrere Ziele entwickelt und sein letztes Update war vor einem Jahr, schau es dir an hier es könnte dir helfen (1, 14 und 68). Ich betrachte im Grunde alles innerhalb des Include-Verzeichnisses als öffentlich und die dort definierte Struktur wird beibehalten. Wenn Sie also Ihrem Beispiel mit GTK-Headern folgen, wird es so etwas wie sein ${CMAKE_CURRENT_SOURCE_DIR}/include/gtk-4.0/gsk/gsk.h, ${CMAKE_CURRENT_SOURCE_DIR}/include/gtk-4.0/gsk/vulkan/gskvulkanrenderer.h.

    – J.Adler

    10. Juli 2021 um 21:01 Uhr


Ich glaube nicht, dass deine Lösung die richtige ist. /usr/include sollte für Ihren Anbieter reserviert sein, um Dateien einzufügen.

Das Richtige ist meiner Meinung nach, den Header zu installieren /usr/local/include und dann den Benutzer anweisen export CPATH="/usr/local/include:${CPATH}".

Es scheint /usr/local/lib wurde automatisch gesucht, aber wenn Sie ein anderes Verzeichnis verwenden möchten export LIBRARY_PATH="/usr/local/lib:${LIBRARY_PATH}" funktioniert ähnlich für die .a-Binärdatei (kann aber je nach Betriebssystem für gemeinsam genutzte Bibliotheken gut funktionieren oder nicht).

Optional, aber umständlicher hinzuzufügen -I /usr/local/include und -L /usr/local/lib beim Kompilieren.

Dies ist eine etwas subjektive Antwort, aber sie hat für mich gut funktioniert.

  • this INSTALL(FILES ${HEADERS} DESTINATION include) fügt die Header-Dateien standardmäßig zu /usr/local/include hinzu, wenn Sie dies ändern möchten, tun Sie Folgendes: make DESTDIR=/home/user/my_include install

    – ady

    13. April 2016 um 22:28 Uhr


Jahre später, mit CMake 3.23, können wir FILE_SET für öffentliche Header verwenden:

project(programming-network)

add_library(programming-network STATIC)

target_include_directories(programming-network PRIVATE "${PROJECT_SOURCE_DIR}")

target_sources(programming-network 
    PRIVATE send_string.c recv_line.c
    PUBLIC FILE_SET HEADERS 
    BASE_DIRS ${PROJECT_SOURCE_DIR}
    FILES publicheader1.h publicheader2.h)

install(TARGETS programming-network FILE_SET HEADERS)

Sehen wir uns nun an, was diese Befehle bewirken:

  • add_library(): definiert den Namen des Ziels, STATIC für eine statische Bibliothek, SHARED für eine gemeinsame Bibliothek, OBJECT für Objekte.

  • target_include_directories(): Diese Zeile hier ist nur dann, wenn Sie Unterverzeichnisse und private Header haben, die sich relativ zum Projektverzeichnis gegenseitig referenzieren. Im Allgemeinen wird dieser Befehl jedoch zum Einfügen externer Header in ein Projekt verwendet.

  • target_sources(): Dieser Befehl wird verwendet, um Definitionsdateien und private Header hinzuzufügen PRIVATE Stichwort. Außerdem wird es verwendet, um öffentliche Header über hinzuzufügen FILE_SET Stichwort. BASE_DIRS besteht darin, den absoluten Pfad öffentlicher Header in einen relativen Pfad umzuwandeln, indem das Basisverzeichnis von ihrem Pfad abgezogen wird. Also dieser öffentliche Header

/home/someuser/programming-network/sub1/publicheader1.h

mit Basisverzeichnis von

/home/someuser/programming-network/

wird eingebaut

/cmake/install/prefix/include/sub1/publicheader.h

Notiz target_sources() kann verwendet werden CMakeLists.txt auch von Unterverzeichnissen.

  • install(): soll Binärdateien, statische/gemeinsam genutzte Bibliotheken und öffentliche Header installieren. Die standardmäßigen Installationsunterverzeichnisse sind bin, lib und include. Das kannst du auch so ändern
install(TARGETS myTarget
        # for executables and dll on Win
        RUNTIME DESTINATION bin
        # shared libraries
        LIBRARY DESTINATION lib
        # for static libraries
        ARCHIVE DESTINATION lib
        # public headers
        INCLUDES DESTINATION include)

Und schließlich wird das Projekt gebaut und installiert mit (für Multikonfigurationsgeneratoren: MS Visual C++, Xcode)

# in project directory
mkdir build
cd build
cmake ..
cmake --build . --config Release
cmake --install . --prefix "/usr/local/" --config Release

Für Generatoren mit einer Konfiguration (Marke, Ninja) lassen Sie das obige weg --config Release Bedingungen und Änderungen cmake .. zu cmake -DCMAKE_BUILD_TYPE=Release ...

Zusätzlich zu der akzeptierten Antwort, wenn Sie viele Bibliotheken erstellen und die set_property Syntax wirft Sie ab. Sie könnten es in ein sehr einfaches Makro packen, wie zum Beispiel:

# File: target_public_headers.cmake
macro(target_public_headers TARGET)
  set_target_properties(${TARGET} PROPERTIES PUBLIC_HEADER "${ARGN}")
endmacro()

Dann können Sie es wie folgt verwenden:

project(myproject)

include(target_public_headers)

add_library(mylib some.c another.c)
target_public_headers(mylib some.h another.h) # <<<<<

# If you're exporting this library then you need to tell
# CMake how to include the "installed" version of the headers.
target_include_directories(mylib
  PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
  PUBLIC $<INSTALL_INTERFACE:some/includepath>
)

INSTALL(TARGETS mylib 
        LIBRARY DESTINATION some/libpath
        PUBLIC_HEADER DESTINATION some/includepath
)

1415280cookie-checkCMAKE – Wie kopiert man die Header-Datei der statischen Bibliothek richtig nach /usr/include?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy