So fügen Sie Include-Verzeichnisse mit CMake richtig hinzu

242

Vor ungefähr einem Jahr habe ich nach Header-Abhängigkeiten in CMake gefragt .

Ich habe kürzlich festgestellt, dass das Problem darin zu bestehen schien, dass CMake diese Header-Dateien als außerhalb des Projekts liegend ansah . Zumindest beim Generieren eines Code :: Blocks-Projekts werden die Header-Dateien nicht im Projekt angezeigt (die Quelldateien). Es scheint mir daher, dass CMake diese Header als außerhalb des Projekts liegend betrachtet und sie nicht in den Abhängigkeiten verfolgt.

Eine schnelle Suche im CMake-Tutorial zeigte nur, include_directorieswas nicht zu tun scheint, was ich wünsche ...

Was ist der richtige Weg, um CMake zu signalisieren, dass ein bestimmtes Verzeichnis zu enthaltende Header enthält und dass diese Header vom generierten Makefile verfolgt werden sollten?

Matthieu M.
quelle
Die an dieser Frage vorgenommenen Änderungen machen sie verwirrend. Die ursprüngliche Frage und Antwort lautete, wie Header-Dateien in einer IDE verfolgt werden. Dies unterscheidet sich erheblich von einer generierten Makefile-Abhängigkeit von fehlenden Header-Dateien und davon, wie dieses Problem behoben werden kann.
fdk1342
@Fred: Ich habe keine Ahnung, wovon du sprichst. Wie die Überarbeitung deutlich zeigt, war der letzte Satz immer da. Bei dieser Frage wurden nur kosmetische Änderungen vorgenommen, und es wurde kein Wort eingeführt (oder entfernt).
Matthieu M.
Dann ist das mein Missverständnis. Mir sah es so aus, als wäre ein ganzer Absatz hinzugefügt worden. Laut stackoverflow.com/questions/13703647/… bestand das allgemeine Verständnis darin, wie die Header-Datei in der IDE aufgelistet wird . Dies hätte sich auf die .cbpProjektdatei bezogen. 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. In einigen Fällen wird dies jedoch falsch sein, da kein vollständiger Präprozessor enthalten ist.
fdk1342

Antworten:

267

Zwei Dinge müssen getan werden.

Fügen Sie zuerst das Verzeichnis hinzu, das aufgenommen werden soll:

target_include_directories(test PRIVATE ${YOUR_DIRECTORY})

Wenn Sie mit einer sehr alten CMake-Version (2.8.10 oder älter) ohne Unterstützung nicht weiterkommen target_include_directories, können Sie include_directoriesstattdessen auch das Legacy verwenden:

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:

set(SOURCES file.cpp file2.cpp ${YOUR_DIRECTORY}/file1.h ${YOUR_DIRECTORY}/file2.h)
add_executable(test ${SOURCES})

Auf diese Weise werden die Header-Dateien als Abhängigkeiten im Makefile und beispielsweise auch im generierten Visual Studio-Projekt angezeigt, sofern Sie eines generieren.

So verwenden Sie diese Header-Dateien für mehrere Ziele:

set(HEADER_FILES ${YOUR_DIRECTORY}/file1.h ${YOUR_DIRECTORY}/file2.h)

add_library(mylib libsrc.cpp ${HEADER_FILES})
target_include_directories(mylib PRIVATE ${YOUR_DIRECTORY})
add_executable(myexec execfile.cpp ${HEADER_FILES})
target_include_directories(myexec PRIVATE ${YOUR_DIRECTORY})
SirDarius
quelle
Ah! Ich wusste, dass es etwas Dummes sein musste. In der Tat habe ich die Header nicht aufgelistet ... Muss ich nur die Header dieser Bibliothek oder auch alle Header auflisten, von denen sie abhängen könnte (zusätzlich zum Deklarieren der Abhängigkeit von der Bibliothek)? Es ist ein wachsendes Projekt und ich fürchte die Idee, allen Abhängigkeiten einen Header hinzuzufügen, wenn ich einen in der Stammbibliothek hinzufüge.
Matthieu M.
Ja, um eine bessere Abhängigkeitsverfolgung zu ermöglichen (z. B. um sicherzustellen, dass das Ändern einer Header-Datei die Kompilierung für alle betroffenen Ziele auslöst). Sie können jedoch cmake-Variablen verwenden, um die Header-Dateien nur einmal aufzulisten und an mehreren Stellen zu verwenden (siehe meine Bearbeitung).
SirDarius
1
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 LIBROOT_HEADER_FILESVariable in liba/CMakefileund libb/CMakefiledann verwenden?
Matthieu M.
2
Das ist falsch, sollten Sie nie benutzen include_directoriesüber target_include_directories. Ersteres legt es rekursiv für alle Ziele in diesem Verzeichnis fest. während letzteres es für ein Ziel setzt. Wenn Sie erstere ausführen, wird der Begriff eines Zieldiagramms in CMake gebrochen und stattdessen auf Nebenwirkungen Ihrer Dateihierarchie zurückgegriffen.
Andy
1
Ich habe die Antwort bearbeitet, um den aktuellen Gedanken widerzuspiegeln, target_include_directoriesmodernen CMake-Code zu bevorzugen . Sie können mich gerne zu einem Chat einladen, wenn Sie mit den Änderungen nicht einverstanden sind.
ComicSansMS
74

Zunächst include_directories()weisen Sie CMake an, das Verzeichnis -Izur Kompilierungsbefehlszeile hinzuzufügen . Zweitens listen Sie die Header in Ihrem add_executable()oder add_library()Anruf auf.

Wenn sich beispielsweise die Quellen Ihres Projekts in befinden srcund Sie Header von benötigen include, können Sie dies folgendermaßen tun:

include_directories(include)

add_executable(MyExec
  src/main.c
  src/other_source.c
  include/header1.h
  include/header2.h
)
Angew ist nicht mehr stolz auf SO
quelle
19
Müssen Sie wirklich Header hinzufügen add_executable? Ich dachte, CMake hat die Abhängigkeiten der Include-Dateien automatisch herausgefunden.
Colin D Bennett
57
@ColinDBennett Sie müssen sie aus Abhängigkeitsgründen nicht auflisten - CMake ermittelt Build-Abhängigkeiten ganz gut, wenn Sie dies nicht tun. Wenn Sie sie jedoch auflisten, werden sie als Teil des Projekts betrachtet und als solche in IDEs aufgeführt (was das Thema der Frage war).
Angew ist nicht mehr stolz auf SO
Zumindest für QtCreator ist es nicht erforderlich, class.h hinzuzufügen, falls eine class.cpp vorhanden ist. Nur lonely.h muss zur Quelle hinzugefügt werden. Siehe Tutorial unter www.th-thielemann.de/cmake
Th. Thielemann
19

CMake ähnelt eher einer Skriptsprache, wenn es mit anderen Methoden zum Erstellen von Makefile (z. B. make oder qmake) verglichen wird. Es ist nicht sehr cool wie Python, aber trotzdem.

Es gibt keinen " richtigen Weg ", wenn man in verschiedenen OpenSource-Projekten nachschaut, wie Leute Verzeichnisse einbinden. Es gibt jedoch zwei Möglichkeiten.

  1. Crude include_directories hängt ein Verzeichnis an das aktuelle Projekt und alle anderen untergeordneten Projekte an, die Sie über eine Reihe von Befehlen add_subdirectory anhängen . Manchmal sagen die Leute, dass ein solcher Ansatz ein Vermächtnis ist.

  2. 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. Ermöglichen Sie auch das Durchführen einer subtilen Konfiguration und das Anhängen einer der folgenden Markierungen für diesen Befehl.

PRIVATE - Nur für dieses angegebene Build-Ziel verwenden

PUBLIC - Verwenden Sie es für ein bestimmtes Ziel und für Ziele, die mit diesem Projekt verknüpft sind

SCHNITTSTELLE - Verwenden Sie diese Option nur für Ziele, die mit dem aktuellen Projekt verknüpft sind

PS:

  1. Mit beiden Befehlen können Sie ein Verzeichnis als SYSTEM markieren, um einen Hinweis darauf zu geben, dass die angegebenen Verzeichnisse keine Warnungen enthalten.

  2. Eine ähnliche Antwort gibt es mit anderen Befehlspaaren target_compile_definitions / add_definitions , target_compile_options / CMAKE_C_FLAGS

Bruziuz
quelle
13

Hinzufügen include_directories("/your/path/here").

Dies ähnelt dem Aufruf gccmit -I/your/path/here/Option.

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 festgefahren. Diese Antwort ist also für Leute, die CMake noch sehr neu und sehr verwirrt sind.

off99555
quelle
7

Ich hatte das gleiche Problem.

Mein Projektverzeichnis war wie folgt:

    --project
    ---Classes
    ----Application
    -----.h and .c files
    ----OtherFolders
    --main.cpp

Und was ich verwendet habe, um die Dateien in all diese Ordner aufzunehmen:

    file(GLOB source_files
            "*.h"
            "*.cpp"
            "Classes/*/*.cpp"
            "Classes/*/*.h"
    )

    add_executable(Server ${source_files})

Und es hat total funktioniert.

Seyed Hussein Mirzaki
quelle
Es ist in modernen cmake (CMake mit Versionen 3.0 und höher) keine gute Idee, sich daran zu erinnern, dass cmake ein "Build-System-Generator" und kein "Build-System" ist, das File Glob verwendet, da File Globs zum Zeitpunkt des Builds und nicht zum Erstellen ausgewertet werden Zeit der Systemgenerierung. Siehe Link: gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1
ggulgulia