327

About a year ago I asked about header dependencies in CMake.

I realized recently that the issue seemed to be that CMake considered those header files to be external to the project. At least, when generating a Code::Blocks project the header files do not appear within the project (the source files do). It therefore seems to me that CMake consider those headers to be external to the project, and does not track them in the depends.

A quick search in the CMake tutorial only pointed to include_directories which does not seem to do what I wish...

What is the proper way to signal to CMake that a particular directory contains headers to be included, and that those headers should be tracked by the generated Makefile?

4

10 回答 10

350

必须做两件事。

首先添加要包含的目录:

target_include_directories(test PRIVATE ${YOUR_DIRECTORY})

如果您在不支持的情况下使用非常旧的 CMake 版本(2.8.10 或更早版本)target_include_directories,您也可以使用旧版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})
于 2012-12-04T13:09:31.407 回答
95

首先,您使用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
)
于 2012-12-04T13:10:33.703 回答
32

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

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

确保在路径周围加上双引号。其他人没有提到这一点,这让我坚持了 2 天。所以这个答案适用于那些对 CMake 非常陌生并且非常困惑的人。

于 2019-04-18T09:30:27.737 回答
26

如果将 CMake 与其他创建 Makefile 的方法(例如 make 或 qmake)进行比较,CMake 更像是一种脚本语言。它不像 Python 那样很酷,但仍然如此。

如果在各种开源项目中查看人们如何包含目录,则没有像“正确方法”这样的东西。但是有两种方法可以做到这一点。

  1. 粗略的include_directories会将一个目录附加到当前项目和您将通过一系列add_subdirectory命令附加的所有其他后代项目。有时人们说这种方法是遗留问题。

  2. 更优雅的方法是使用target_include_directories。它允许为特定项目/目标附加目录,而不会(可能)不必要的继承或各种包含目录的冲突。还允许执行甚至是细微的配置并为此命令附加以下标记之一。

PRIVATE - 仅用于此指定的构建目标

PUBLIC - 将其用于指定目标和与该项目链接的目标

INTERFACE -- 仅用于与当前项目链接的目标

PS:

  1. 这两个命令都允许将目录标记为 SYSTEM 以提示指定目录将包含警告不是您的业务。

  2. 类似的答案是使用其他命令对target_compile_definitions / add_definitionstarget_compile_options / CMAKE_C_FLAGS

于 2017-08-11T13:49:21.527 回答
11

我有同样的问题。

我的项目目录是这样的:

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

以及我曾经将文件包含在所有这些文件夹中的内容:

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

    add_executable(Server ${source_files})

它完全奏效了。

于 2018-06-24T09:36:31.603 回答
9

项目结构

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

于 2021-07-13T10:14:31.750 回答
2

这对我有用:

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})
于 2020-07-24T14:58:48.123 回答
0

还有另一种选择:

set_property(
    TARGET MyApp
    APPEND PROPERTY
        INCLUDE_DIRECTORIES "${CMAKE_CURRENT_LIST_DIR}/src"
)  
于 2021-06-22T14:52:53.043 回答
0

不要忘记包括${CMAKE_CURRENT_LIST_DIR}. 这就是给我带来问题的原因。

示例应该是这样的:

target_include_directories(projectname
    PUBLIC "${CMAKE_CURRENT_LIST_DIR}/include"                          
)

PUBLIC 用于您希望包含在父项目中的依赖项。对于那些你不知道的人来说是私人的。

于 2021-11-20T20:24:27.597 回答
-2

我正在使用 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)

通过这样做,程序编译成功。

于 2021-03-18T19:08:26.503 回答