如何使用CMake正确添加包含目录

时间:2012-12-04 13:04:54

标签: c++ ubuntu cmake

大约一年前,我问过header dependencies in CMake

我最近意识到问题似乎是CMake认为那些头文件是外部到项目中。至少,在生成Code :: Blocks项目时,头文件不会出现在项目中(源文件会出现)。因此,在我看来,CMake认为那些标题是外部到项目中,并且不会在依赖项中跟踪它们。

在CMake教程中的快速搜索只指向include_directories,它似乎没有按照我的意愿......

向CMake发出信号通知特定目录是否包含要包含的标头的正确方法是什么,并且生成的Makefile应该跟踪这些标头?

8 个答案:

答案 0 :(得分:204)

必须做两件事。

首先添加要包含的目录:

target_include_directories(test PRIVATE ${YOUR_DIRECTORY})

如果您遇到不支持target_include_directories的非常旧的CMake版本(2.8.10或更早版本),您也可以使用旧版include_directories代替:

include_directories(${YOUR_DIRECTORY})

然后,您还必须将头文件添加到当前目标的源文件列表中,例如:

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

这样,头文件将在Makefile中显示为依赖项,例如在生成的Visual Studio项目中,如果生成一个。

如何将这些头文件用于多个目标:

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

答案 1 :(得分:57)

首先,使用include_directories()告诉CMake将目录-I添加到编译命令行。其次,您可以在add_executable()add_library()来电中列出标题。

例如,如果您的项目来源位于src,并且您需要来自include的标题,则可以这样做:

include_directories(include)

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

答案 2 :(得分:4)

我遇到了同样的问题。

我的项目目录如下:

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

过去我在所有这些文件夹中都包含这些文件的内容:

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

    add_executable(Server ${source_files})

它完全有效。

答案 3 :(得分:2)

添加include_directories("/your/path/here")

这类似于使用gcc选项调用-I/your/path/here/

确保在路径两边加上双引号。其他人没有提及,这让我呆了2天。因此,此答案适用于刚接触CMake且非常困惑的人。

答案 4 :(得分:0)

这对我有用:

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

答案 5 :(得分:0)

另一种选择:

set_property(
    TARGET MyApp
    APPEND PROPERTY
        INCLUDE_DIRECTORIES "${CMAKE_CURRENT_LIST_DIR}/src"
)  

答案 6 :(得分:0)

项目结构

.
├── 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

怎么做

1.顶层 CMakeLists.txt 与 Recipe 1 非常相似,代码重用与函数和宏

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.Targets和sources在src/CMakeLists.txt中定义(转换目标除外)

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
  )

3.转换库定义在external/CMakeLists.txt

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. src/CMakeLists.txt 文件添加了更多子目录,这些子目录又包含 CMakeLists.txt 文件。它们在结构上都相似; src/evolution/CMakeLists.txt 包含以下内容:

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.单元测试在tests/CMakeLists.txt中注册

add_executable(cpp_test test.cpp)

target_link_libraries(cpp_test evolution)

add_test(
  NAME
    test_evolution
  COMMAND
    $<TARGET_FILE:cpp_test>
  )

如何运行

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

参考:https://github.com/sun1211/cmake_with_add_subdirectory

答案 7 :(得分:-1)

我正在使用 CLion,我的项目结构如下:

--main.cpp
--Class.cpp
--Class.h
--CMakeLists.txt

CMakeLists.txt 变化之前

add_executable(ProjectName main.cpp)

CMakeLists.txt 变化之后

add_executable(ProjectName main.cpp Class.cpp Class.h)

这样程序就编译成功了。