CMAKE – Wie kopiert man die Header-Datei der statischen Bibliothek richtig nach /usr/include?
Lesezeit: 8 Minuten
Miroslav Stuten
Ich steige in die CMAKE-Nutzung mit C ein und erstelle eigentlich zwei sehr kleine statische Bibliotheken.
Mein Ziel ist:
Die Bibliotheken werden kompiliert und in *.a-Dateien gelinkt. [THIS
WORKS]
Dann möchte ich diese *.a-Dateien nach /usr/local/lib kopieren [THIS ALSO WORKS]
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:
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
film8620
Ein besserer Weg für die neueste cmake-Version ist die Verwendung von Zielen PUBLIC_HEADER Eigenschaften.
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:
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
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)
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:
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
)
14152800cookie-checkCMAKE – Wie kopiert man die Header-Datei der statischen Bibliothek richtig nach /usr/include?yes
Warum nicht einfach eine Zeile hinzufügen
Makefile
unterinstall: \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=/usr
dann 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