大约一年前,我问过CMake中的头依赖关系。

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

在CMake教程中快速搜索只指向include_directories,这似乎不是我想要的…

向CMake发出特定目录包含要包含的头文件,以及生成的Makefile应该跟踪这些头文件的正确方法是什么?


当前回答

在更新的CMake版本中,我们可以将包含路径限制为target,例如:

target_include_directories(MyApp PRIVATE "${CMAKE_CURRENT_LIST_DIR}/myFolder")

我的意思是,如果CMakeLists.txt有多个目标,否则,包含路径不与其他CMakeLists.txt脚本共享,它足以做一些事情,如:

include_directories("${CMAKE_CURRENT_LIST_DIR}/myFolder")

然而,也许我们可以模拟target_include_directories(…)在CMake 2.8.10或更老版本中的作用,比如:

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

所有这些都完成了,但似乎如果你想要源文件被重新编译,一旦他们使用的任何头文件被改变,所有这样的头文件也需要添加到每个目标,比如:

set(SOURCES src/main.cpp)

set(HEADERS
    ${CMAKE_CURRENT_LIST_DIR}/myFolder/myHeaderFile.h
    ${CMAKE_CURRENT_LIST_DIR}/myFolder/myOtherHeader.h
)

add_executable(MyApp ${SOURCES} ${HEADERS})

我的意思是,如果CMake愿意,它可以自动检测到这样的头文件,因为它无论如何都会解析项目的C/ c++文件。

其他回答

我也有同样的问题。

我的项目目录是这样的:

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

这完全奏效了。

首先,使用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
)

我使用的是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)

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

项目结构

.
├── 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非常类似于配方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.目标和源定义在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
    ${CMAKE_CURRENT_LIST_DIR}/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

添加include_directories(“/ /路径”)。

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

确保在路径周围加上双引号。其他人没有提到这一点,这让我被困了两天。所以这个答案是给那些对CMake非常陌生和非常困惑的人的。