So fügen Sie Include-Verzeichnisse mit CMake richtig hinzu
Lesezeit: 10 Minuten
Matthias M.
Vor ungefähr einem Jahr fragte ich nach Header-Abhängigkeiten in CMake.
Mir wurde kürzlich klar, dass das Problem darin zu liegen schien, dass CMake diese Header-Dateien als extern zum Projekt. Zumindest erscheinen beim Generieren eines Code::Blocks-Projekts die Header-Dateien nicht innerhalb des Projekts (die Quelldateien tun dies). Es scheint mir daher, dass CMake diese Header als extern zum Projekt und verfolgt sie nicht in den Abhängigkeiten.
Eine schnelle Suche im CMake-Tutorial hat nur darauf hingewiesen include_directories das scheint nicht das zu tun, was ich wünsche …
Was ist der richtige Weg, um CMake zu signalisieren, dass ein bestimmtes Verzeichnis Header enthält, die eingeschlossen werden sollen, und dass diese Header vom generierten Makefile verfolgt werden sollen?
Die an dieser Frage vorgenommenen Änderungen machen sie verwirrend. Die ursprüngliche Frage und Antworten waren, wie man Header-Dateien in einer IDE verfolgt. Dies unterscheidet sich deutlich von einem generierten Makefile mit fehlenden Header-Dateiabhängigkeiten und der Lösung dieses Problems.
– fdk1342
1. Januar 2019 um 17:39 Uhr
@Fred: Ich habe keine Ahnung, wovon du sprichst. Wie die Edit-Revision deutlich zeigt, hat der letzte Satz immer war dort. An dieser Frage wurden nur kosmetische Änderungen vorgenommen, und es wurde kein Wort hinzugefügt (oder entfernt).
– Matthias M.
1. Januar 2019 um 17:45 Uhr
Dann ist das mein Missverständnis. Es sah für mich so aus, als wäre ein ganzer Absatz hinzugefügt worden. stackoverflow.com/questions/13703647/… sagt, dass das gemeinsame Verständnis war, wie die Header-Datei in der IDE aufgelistet wird. Dies hätte sich auf die bezogen .cbp Projektdatei. Wenn der cmake-Abhängigkeitsscanner eine Header-Datei nicht korrekt als Abhängigkeit für ein Makefile identifiziert, gibt es Möglichkeiten, dies zu beheben, aber in einigen Fällen wird er falsch angezeigt, da er keinen vollständigen Präprozessor enthält.
– fdk1342
1. Januar 2019 um 18:28 Uhr
SirDarius
Zwei Dinge müssen getan werden.
Fügen Sie zuerst das einzubindende Verzeichnis hinzu:
Falls Sie mit einer sehr alten CMake-Version (2.8.10 oder älter) ohne Unterstützung für target_include_directorieskönnen Sie auch das Vermächtnis verwenden include_directories stattdessen:
include_directories(${YOUR_DIRECTORY})
Dann müssen Sie auch die Header-Dateien zur Liste Ihrer Quelldateien für das aktuelle Ziel hinzufügen, zum Beispiel:
Auf diese Weise erscheinen die Header-Dateien als Abhängigkeiten im Makefile und beispielsweise auch im generierten Visual Studio-Projekt, falls Sie eines generieren.
So verwenden Sie diese Header-Dateien für mehrere Ziele:
Ah! Ich wusste, es muss etwas Dummes sein. Tatsächlich habe ich die Header nicht aufgelistet … Muss ich nur die Header dieser Bibliothek auflisten oder auch alle Header, von denen sie abhängen könnte (zusätzlich zur Deklaration der Abhängigkeit von der Bibliothek)? Es ist ein wachsendes Projekt und ich fürchte die Idee, einen Header hinzuzufügen alle die Abhängigkeiten, wenn ich eine in der Root-Bibliothek hinzufüge.
– Matthias M.
4. Dezember 2012 um 13:13 Uhr
Meine Frage war eher in dem Sinne, dass ich mehrere Bibliotheken habe, die voneinander abhängen: libroot, liba hängt von libroot ab, libb hängt von libroot ab. Kann ich die verwenden LIBROOT_HEADER_FILES variabel ein liba/CMakefile und libb/CMakefile dann ?
– Matthias M.
4. Dezember 2012 um 13:37 Uhr
Das ist falsch, das solltest du noch nie verwenden include_directories über target_include_directories. Ersteres setzt es rekursiv für alle Ziele in diesem Verzeichnis; wohingegen letzteres es für ein Ziel festlegt. Ersteres bricht die Vorstellung eines Zieldiagramms in CMake und verlässt sich stattdessen auf Nebeneffekte in Ihrer Dateihierarchie.
– Andy
10. August 2017 um 1:47 Uhr
Ich habe die Antwort bearbeitet, um den aktuellen Begriff des Vorziehens widerzuspiegeln target_include_directories für modernen CMake-Code. Fühlen Sie sich frei, mich zu einem Chat einzuladen, wenn Sie mit den Änderungen nicht einverstanden sind.
– ComicSansMS
6. Februar 2018 um 12:10 Uhr
@donturner Sie müssen nicht hinzufügen .h Dateien hinein add_executable. Aber es hat den netten Vorteil, dass die Dateien in angezeigt werden Visual Studio Projekte am erwarteten Standort. Makefiles nutzt das Interne cmake -E cmake_depends um Abhängigkeiten aus den Quelldateien (Header-Dateien in add_executable werden übersprungen). Es sind bekannt Themen damit der Scanner. Auch ` der Makefile-Generator-Abhängigkeits-Scanner von CMake führt nur eine ungefähre Vorverarbeitung durch. ` Berechnete Header enthalten und so etwas wird nicht funktionieren.
– fdk1342
1. Januar 2019 um 7:12 Uhr
Angew ist nicht mehr stolz auf SO
Erstens verwenden Sie include_directories() um CMake anzuweisen, das Verzeichnis als hinzuzufügen -I zur Kompilierungsbefehlszeile. Zweitens listen Sie die Überschriften in Ihrer auf add_executable() oder add_library() Anruf.
Wenn sich beispielsweise die Quellen Ihres Projekts in srcund Sie benötigen Header von includedu könntest es so machen:
Müssen Sie wirklich Header hinzufügen? add_executable? Ich dachte, CMake hat die Abhängigkeiten der Include-Datei automatisch herausgefunden.
– Colin D. Bennett
2. November 2013 um 17:40 Uhr
@ColinDBennett Sie müssen sie nicht aus Abhängigkeitsgründen auflisten – CMake erkennt Build-Abhängigkeiten gut, wenn Sie dies nicht tun. Wenn Sie sie jedoch auflisten, gelten sie als Teil des Projekts und werden als solche in IDEs aufgeführt (was das Thema der Frage war).
– Angew ist nicht mehr stolz auf SO
2. November 2013 um 18:57 Uhr
Zumindest für QtCreator ist es nicht notwendig, class.h hinzuzufügen, falls eine class.cpp existiert. Nur lonely.h muss zur Quelle hinzugefügt werden. Siehe Anleitung unter www.th-thielemann.de/cmake
– Th. Thielemann
22. Januar 2018 um 18:47 Uhr
Addieren include_directories("/your/path/here").
Dies ist ähnlich wie beim Anrufen gcc mit -I/your/path/here/ Möglichkeit.
Stellen Sie sicher, dass Sie den Pfad in doppelte Anführungszeichen setzen. Andere Leute haben das nicht erwähnt und es hat mich 2 Tage lang feststecken lassen. Diese Antwort ist also für Leute, die CMake noch nicht kennen und sehr verwirrt sind.
außer es schlägt zufällig die Hälfte der Zeit fehl. =/
– Bad Zen
17. März 2021 um 21:21 Uhr
Konstantin Burlachenko
CMake ähnelt eher einer Skriptsprache, wenn man es mit anderen Methoden zum Erstellen von Makefile vergleicht (z. B. make oder qmake). Es ist nicht sehr cool wie Python, aber immerhin.
Es gibt keine “richtige Weg” Wenn Sie in verschiedenen Open-Source-Projekten nachsehen, wie Leute Verzeichnisse einschließen. Aber es gibt zwei Möglichkeiten, dies zu tun.
Roh include_directories wird ein Verzeichnis an das aktuelle Projekt und alle anderen untergeordneten Projekte anhängen, die Sie über eine Reihe von anhängen werden add_subdirectory Befehle. Manchmal sagen die Leute, dass ein solcher Ansatz ein Vermächtnis ist.
Ein eleganterer Weg ist mit target_include_directories. Es ermöglicht das Anhängen eines Verzeichnisses für ein bestimmtes Projekt/Ziel ohne (möglicherweise) unnötige Vererbung oder Kollision verschiedener Include-Verzeichnisse. Erlauben Sie auch eine subtile Konfiguration und hängen Sie eine der folgenden Markierungen für diesen Befehl an.
PRIVAT – Nur für dieses angegebene Build-Ziel verwenden
ÖFFENTLICH ZUGÄNGLICH – Verwenden Sie es für ein bestimmtes Ziel und für Ziele, die mit diesem Projekt verknüpft sind
SCHNITTSTELLE — Verwenden Sie es nur für Ziele, die mit dem aktuellen Projekt verknüpft sind
PS:
Beide Befehle erlauben es, ein Verzeichnis als SYSTEM zu markieren, um einen Hinweis darauf zu geben, dass es nicht Ihre Sache ist, dass bestimmte Verzeichnisse Warnungen enthalten.
Sich daran zu erinnern, dass cmake ein „Build-System-Generator“ und kein „Build-System“ ist, das File-Glob verwendet, ist in modernem cmake (CMake mit Version 3.0 und höher) keine gute Idee, da File-Globs zur „Build“-Zeit und nicht zur „Build“-Zeit ausgewertet werden Zeit der Systemgenerierung. Siehe Link: gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1
– Ggulgulie
21. März 2020 um 10:34 Uhr
Einfach hinzufügen CONFIGURE_DEPENDS.
– letmaik
6. Juli 2020 um 10:33 Uhr
Struktur des Projekts
.
├── CMakeLists.txt
├── external //We simulate that code is provided by an "external" library outside of src
│ ├── CMakeLists.txt
│ ├── conversion.cpp
│ ├── conversion.hpp
│ └── README.md
├── src
│ ├── CMakeLists.txt
│ ├── evolution //propagates the system in a time step
│ │ ├── CMakeLists.txt
│ │ ├── evolution.cpp
│ │ └── evolution.hpp
│ ├── initial //produces the initial state
│ │ ├── CMakeLists.txt
│ │ ├── initial.cpp
│ │ └── initial.hpp
│ ├── io //contains a function to print a row
│ │ ├── CMakeLists.txt
│ │ ├── io.cpp
│ │ └── io.hpp
│ ├── main.cpp //the main function
│ └── parser //parses the command-line input
│ ├── CMakeLists.txt
│ ├── parser.cpp
│ └── parser.hpp
└── tests //contains two unit tests using the Catch2 library
├── catch.hpp
├── CMakeLists.txt
└── test.cpp
Wie es geht
1. Die CMakeLists.txt der obersten Ebene ist Rezept 1, Wiederverwendung von Code mit Funktionen und Makros, sehr ähnlich
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(recipe-07 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(GNUInstallDirs)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
# defines targets and sources
add_subdirectory(src)
# contains an "external" library we will link to
add_subdirectory(external)
# enable testing and define tests
enable_testing()
add_subdirectory(tests)
2.Ziele und Quellen sind in src/CMakeLists.txt definiert (außer dem Konvertierungsziel)
3.Die Konvertierungsbibliothek ist in external/CMakeLists.txt definiert
add_library(conversion "")
target_sources(conversion
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/conversion.cpp
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/conversion.hpp
)
target_include_directories(conversion
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
)
4.Die Datei src/CMakeLists.txt fügt weitere Unterverzeichnisse hinzu, die wiederum CMakeLists.txt-Dateien enthalten. Sie sind alle ähnlich aufgebaut; src/evolution/CMakeLists.txt enthält Folgendes:
add_library(evolution "")
target_sources(evolution
PRIVATE
evolution.cpp
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/evolution.hpp
)
target_include_directories(evolution
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
)
5. Die Komponententests werden in tests/CMakeLists.txt registriert
add_executable(cpp_test test.cpp)
target_link_libraries(cpp_test evolution)
add_test(
NAME
test_evolution
COMMAND
$<TARGET_FILE:cpp_test>
)
Sich daran zu erinnern, dass cmake ein „Build-System-Generator“ und kein „Build-System“ ist, das File-Glob verwendet, ist in modernem cmake (CMake mit Version 3.0 und höher) keine gute Idee, da File-Globs zur „Build“-Zeit und nicht zur „Build“-Zeit ausgewertet werden Zeit der Systemgenerierung. Siehe Link: gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1
– Ggulgulie
21. März 2020 um 10:34 Uhr
Einfach hinzufügen CONFIGURE_DEPENDS.
– letmaik
6. Juli 2020 um 10:33 Uhr
Bryan Jyh Herng Chong
Das hat bei mir funktioniert:
set(SOURCE main.cpp)
add_executable(${PROJECT_NAME} ${SOURCE})
# target_include_directories must be added AFTER add_executable
target_include_directories(${PROJECT_NAME} PUBLIC ${INTERNAL_INCLUDES})
9871100cookie-checkSo fügen Sie Include-Verzeichnisse mit CMake richtig hinzuyes
Die an dieser Frage vorgenommenen Änderungen machen sie verwirrend. Die ursprüngliche Frage und Antworten waren, wie man Header-Dateien in einer IDE verfolgt. Dies unterscheidet sich deutlich von einem generierten Makefile mit fehlenden Header-Dateiabhängigkeiten und der Lösung dieses Problems.
– fdk1342
1. Januar 2019 um 17:39 Uhr
@Fred: Ich habe keine Ahnung, wovon du sprichst. Wie die Edit-Revision deutlich zeigt, hat der letzte Satz immer war dort. An dieser Frage wurden nur kosmetische Änderungen vorgenommen, und es wurde kein Wort hinzugefügt (oder entfernt).
– Matthias M.
1. Januar 2019 um 17:45 Uhr
Dann ist das mein Missverständnis. Es sah für mich so aus, als wäre ein ganzer Absatz hinzugefügt worden. stackoverflow.com/questions/13703647/… sagt, dass das gemeinsame Verständnis war, wie die Header-Datei in der IDE aufgelistet wird. Dies hätte sich auf die bezogen
.cbp
Projektdatei. Wenn der cmake-Abhängigkeitsscanner eine Header-Datei nicht korrekt als Abhängigkeit für ein Makefile identifiziert, gibt es Möglichkeiten, dies zu beheben, aber in einigen Fällen wird er falsch angezeigt, da er keinen vollständigen Präprozessor enthält.– fdk1342
1. Januar 2019 um 18:28 Uhr