417 Stimmen

Wie man mit CMake Include-Verzeichnisse richtig hinzufügt

Vor etwa einem Jahr fragte ich nach Header-Abhängigkeiten in CMake .

Vor kurzem habe ich festgestellt, dass das Problem darin zu liegen scheint, dass CMake diese Header-Dateien als extern zu dem Projekt. Zumindest bei der Erstellung eines Code::Blocks-Projekts erscheinen die Header-Dateien nicht im Projekt (die Quelldateien schon). 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 zeigte nur auf include_directories was nicht das zu tun scheint, was ich mir wünsche...

Wie kann man CMake signalisieren, dass ein bestimmtes Verzeichnis Header enthält, die in das Makefile aufgenommen werden sollen, und dass diese Header von dem generierten Makefile verfolgt werden sollen?

426voto

SirDarius Punkte 38778

Zwei Dinge müssen getan werden.

Fügen Sie zunächst das Verzeichnis hinzu, das einbezogen werden soll:

target_include_directories(test PRIVATE ${YOUR_DIRECTORY})

Für den Fall, dass Sie mit einer sehr alten CMake-Version (2.8.10 oder älter) ohne Unterstützung für target_include_directories verwenden, können Sie auch die alte Version include_directories stattdessen:

include_directories(${YOUR_DIRECTORY})

Dann müssen Sie z.B. auch die Header-Dateien in die Liste Ihrer Quelldateien für das aktuelle Ziel aufnehmen:

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

Auf diese Weise erscheinen die Headerdateien als Abhängigkeiten im Makefile und zum Beispiel auch im generierten Visual Studio Projekt, wenn Sie eines generieren.

Wie man diese Header-Dateien für verschiedene Ziele verwendet:

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})

109voto

Erstens, Sie verwenden include_directories() um CMake anzuweisen, das Verzeichnis als -I in die Befehlszeile der Kompilierung einfügen. Zweitens listen Sie die Header in Ihrem add_executable() o add_library() anrufen.

Wenn sich die Quellen Ihres Projekts beispielsweise in src und Sie benötigen Kopfzeilen von include könnte man es so machen:

include_directories(include)

add_executable(MyExec
  src/main.c
  src/other_source.c
  include/header1.h
  include/header2.h
)

60voto

sun1211 Punkte 593

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 man es macht

1. Die oberste CMakeLists.txt ist sehr ähnlich zu Rezept 1, Code-Wiederverwendung mit Funktionen und Makros

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. die Ziele und Quellen sind in src/CMakeLists.txt definiert (außer dem Konvertierungsziel)

add_executable(automata main.cpp)

add_subdirectory(evolution)
add_subdirectory(initial)
add_subdirectory(io)
add_subdirectory(parser)

target_link_libraries(automata
  PRIVATE
    conversion
    evolution
    initial
    io
    parser
  )

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}
  )

Die Datei src/CMakeLists.txt fügt weitere Unterverzeichnisse hinzu, die ihrerseits CMakeLists.txt-Dateien enthalten. Sie sind alle ähnlich aufgebaut; src/evolution/CMakeLists.txt enthält die folgenden:

add_library(evolution "")

target_sources(evolution
  PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}/evolution.cpp
  PUBLIC
    ${CMAKE_CURRENT_LIST_DIR}/evolution.hpp
  )
target_include_directories(evolution
  PUBLIC
    ${CMAKE_CURRENT_LIST_DIR}
  )

Die Einheitstests 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>
  )

Wie man es ausführt

$ mkdir -p build
$ cd build
$ cmake ..
$ cmake --build .

Siehe dazu: https://github.com/sun1211/cmake_with_add_subdirectory

39voto

off99555 Punkte 3261

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

Dies ist vergleichbar mit dem Aufruf von gcc avec -I/your/path/here/ Option.

Stellen Sie sicher, dass Sie den Pfad in Anführungszeichen setzen. Andere Leute haben das nicht erwähnt, und ich saß 2 Tage lang fest. Diese Antwort ist also für Leute, die sehr neu in CMake sind und sehr verwirrt.

30voto

CMake ist eher eine Skriptsprache, wenn man es mit anderen Methoden zur Erstellung von Makefiles (z.B. make oder qmake) vergleicht. Es ist nicht ganz so cool wie Python, aber immerhin.

Es gibt keine " richtige Art "Wenn man in verschiedenen Open-Source-Projekten nachschaut, wie die Leute Verzeichnisse einbinden. Aber es gibt zwei Möglichkeiten, dies zu tun.

  1. Rohöl include_verzeichnisse wird ein Verzeichnis an das aktuelle Projekt und alle anderen Nachfolgeprojekte anhängen, das Sie über eine Reihe von add_subdirectory Befehle. Manchmal wird gesagt, dass ein solcher Ansatz veraltet 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 Überschneidung verschiedener Include-Verzeichnisse. Erlaubt auch die Durchführung einer subtilen Konfiguration und das Anhängen einer der folgenden Markierungen für diesen Befehl.

PRIVAT - nur für dieses angegebene Build-Ziel verwenden

PUBLIC - Verwendung für das angegebene Ziel und für Ziele, die mit diesem Projekt verknüpft sind

INTERFACE -- nur für Ziele verwenden, die mit dem aktuellen Projekt verknüpft sind

PS:

  1. Beide Befehle erlauben es, ein Verzeichnis als SYSTEM zu markieren, um einen Hinweis darauf zu geben, dass es Sie nichts angeht, dass bestimmte Verzeichnisse Warnungen enthalten.

  2. Eine ähnliche Antwort gibt es bei anderen Befehlspaaren ziel_kompilieren_definitionen / add_definitions , target_compile_options / CMAKE_C_FLAGS

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X