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


242

大约一年前,我询问了CMake中的标头依赖性

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

在CMake教程中快速搜索仅指出了include_directories哪些似乎并没有达到我的期望...

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


对这个问题所做的编辑使它变得混乱。最初的问题和答案是如何在IDE中跟踪头文件。这与生成的缺少头文件依赖项的Makefile以及如何解决该问题完全不同。
fdk1342

@Fred:我不知道你在说什么。正如编辑修订版清楚显示的那样,最后一句话一直在那里。仅对这个问题进行了修饰编辑,并且没有引入(或删除)任何单词。
Matthieu M.19年

那就是我的误会。在我看来,似乎增加了整段。 stackoverflow.com/questions/13703647/…说的普遍理解是如何在IDE中列出头文件。这本来是指.cbp项目文件。现在,如果cmake依赖项扫描程序无法正确地将头文件标识为Makefile的依赖项,则可以通过多种方法来解决该问题,但在某些情况下,它将出错,因为它不包含完整的预处理程序。
fdk1342

Answers:


267

必须做两件事。

首先添加要包含的目录:

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

啊! 我知道那一定是愚蠢的。确实,我没有列出标头...我是否只需要列出该库的标头,或者它可能依赖的所有标头(在声明对库的依赖性之外)?这是一个不断发展的项目,当我在根库中添加一个头文件时,我非常讨厌在所有依赖项中添加头文件的想法。
Matthieu M. 2012年

为了允许更好的依赖关系跟踪(例如,确保修改头文件触发所有受影响目标的编译),可以。但是,您可以使用cmake变量仅列出一次头文件,并在多个地方使用它们,请参阅我的编辑。
SirDarius 2012年

1
我的问题更多的是说我有几个相互依赖的库:libroot,liba依赖于libroot,libb依赖于libroot。我可以使用LIBROOT_HEADER_FILES变量liba/CMakefilelibb/CMakefile呢?
Matthieu M.

2
这是错误的,永远不要使用include_directoriesover target_include_directories。前者为该目录中的所有目标递归设置;而后者将其设置为目标。前者打破了CMake中目标图的概念,而是依赖于文件层次结构的副作用。
安迪

1
我编辑了答案,以反映当前偏爱target_include_directories现代CMake代码的想法。如果您不同意这些更改,请随时邀请我聊天。
ComicSansMS

74

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

19
您确实需要向其中添加标头add_executable吗?我以为CMake会自动找出包含文件的依赖性。
Colin D Bennett

57
@ColinDBennett不必出于依赖关系的原因而列出它们-CMake会找出构建依赖关系,如果没有的话。但是,如果您列出它们,它们将被视为项目的一部分,并且将在IDE中被列出(这是问题的主题)。
Angew不再为SO

至少对于QtCreator,如果class.cpp存在,则不必添加class.h。只需要将lonely.h添加到源代码中。参见教程,网址
Th。蒂勒曼

19

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

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

  1. 原始的include_directories将目录添加到当前项目以及所有其他后代项目,您将通过一系列add_subdirectory命令将其添加。有时人们会说这种方法是遗留的。

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

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

PUBLIC-将其用于指定目标以及与此项目链接的目标

接口 -仅将其用于与当前项目链接的目标

PS:

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

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


13

include_directories("/your/path/here")

这类似于gcc通过-I/your/path/here/ option。

确保在路径两边加上双引号。其他人没有提及,这让我呆了2天。因此,此答案适用于对CMake还是很陌生的人。


7

我有同样的问题。

我的项目目录如下:

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

它完全有效。


记住cmake是使用文件glob的“构建系统生成器”,而不是“构建系统”,在现代cmake(版本3.0及更高版本的CMake)中不是一个好主意,因为文件glob是在“构建”时而不是“构建”时评估的系统生成时间。参见链接:gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1
ggulgulia
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.