使用 cmake 处理头文件依赖关系

发布于 2024-12-05 04:55:15 字数 1641 浏览 1 评论 0原文

我正在一个小型 C++ 项目上使用 CMake,到目前为止,它运行得很好...有一个转折:x

当我更改头文件时,通常需要重新编译许多源文件(直接或间接包含它的文件),然而,cmake 似乎只检测到一些要重新编译的源文件,从而导致损坏状态。我可以通过清除项目并从头开始重建来解决这个问题,但这规避了使用 make 实用程序的目标:仅重新编译所需的内容。

因此,我想我做错了什么。

我的项目组织起来非常简单:

  • 一个顶级目录,其中包含所有资源,主 CMakeLists.txt 位于
  • 一个“include”目录,其中所有公共标头都位于(在各个子目录中)
  • 一个“src”目录,其中所有源文件的子目录都在,src CMakeLists.txt 位于
  • “src”目录中的每个子目录中一个 CMakeLists.txt

主目录有:

cmake_minimum_required(VERSION 2.8)

project(FOO)

set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)

# Compiler Options
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -std=c++0x -Wall -Wextra -Werror")

include_directories($(FOO_SOURCE_DIR)/include)

add_subdirectory(src)

“src”目录:

add_subdirectory(sub1)
add_subdirectory(sub2)
add_subdirectory(sub3)
add_subdirectory(sub4)

add_executable(foo main.cpp)

target_link_libraries(foo sub1 sub2 sub3 sub4)

其中 sub4 取决于sub3 依赖于 sub2 ,而 sub2 依赖于 sub1

以及子目录(sub3)的示例:

set(SUB3_SRCS
    File1.cpp
    File2.cpp
    File3.cpp
    File4.cpp
    File5.cpp
    File6.cpp
    )

add_library(sub3 ${SUB3_SRCS})

target_link_libraries(sub3 sub1 sub2)

如果有人能指出我的内容,我会很高兴对我来说错误的是,在这里或在 CMake 上搜索没有产生任何结果,所以我想这很容易或者应该开箱即用...

(作为参考,我在 MSYS 上使用 cmake 版本 2.8.2)

编辑< /strong>:

感谢比尔的建议我检查了CMake生成的depend.make文件,确实缺少(严重)。这是一个示例:

src/sub3/CMakeFiles/sub3.dir/File1.cpp.obj: ../src/sub3/File1.cpp

是的,仅此而已,根本没有引用任何包含内容:x

I am using CMake on a small C++ project and so far it works great... with one twist :x

When I change a header file, it typically requires recompiling a number of sources files (those which include it, directly or indirectly), however it seems that cmake only detects some of the source files to be recompiled, leading to a corrupted state. I can work around this by wiping out the project and rebuilding from scratch, but this circumvents the goal of using a make utility: only recompiling what is needed.

Therefore, I suppose I am doing something wrong.

My project is very simply organized:

  • a top directory where all resources sit, the main CMakeLists.txt sits there
  • a "include" directory where all public headers lies (in various subdirectories)
  • a "src" directory where all the subdirectories for sources files are, the src CMakeLists.txt sits there
  • a CMakeLists.txt per subdirectory in the "src" directory

The main directory has:

cmake_minimum_required(VERSION 2.8)

project(FOO)

set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)

# Compiler Options
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -std=c++0x -Wall -Wextra -Werror")

include_directories($(FOO_SOURCE_DIR)/include)

add_subdirectory(src)

The "src" directory:

add_subdirectory(sub1)
add_subdirectory(sub2)
add_subdirectory(sub3)
add_subdirectory(sub4)

add_executable(foo main.cpp)

target_link_libraries(foo sub1 sub2 sub3 sub4)

Where sub4 depends on sub3 which depends on sub2 which depends on sub1

And an example of a subdirectory (sub3):

set(SUB3_SRCS
    File1.cpp
    File2.cpp
    File3.cpp
    File4.cpp
    File5.cpp
    File6.cpp
    )

add_library(sub3 ${SUB3_SRCS})

target_link_libraries(sub3 sub1 sub2)

I'd be glad if anyone could point my mistake to me, searching here or on CMake didn't yield anything so I guess it's very easy or should work out of the box...

(for reference, I am using cmake version 2.8.2 on MSYS)

EDIT:

Thanks to Bill's suggestion I have checked the depend.make file generated by CMake, and it is indeed lacking (severely). Here is an example:

src/sub3/CMakeFiles/sub3.dir/File1.cpp.obj: ../src/sub3/File1.cpp

Yep, that's all, none of the includes were referenced at all :x

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

甜扑 2024-12-12 04:55:15

您应该查看二叉树中的 depend.make 文件。它将位于 CMakeFiles/target.dir/depend.make 中。尝试找到其中一个缺少您认为应该具有的 .h 文件的文件。然后为 cmake 创建错误报告或通过电子邮件发送到 cmake 邮件列表。

You should look at the depend.make files in your binary tree. It will be in CMakeFiles/target.dir/depend.make. Try to find one of those that is missing a .h file that you think it should have. Then create a bug report for cmake or email the cmake mailing list.

×纯※雪 2024-12-12 04:55:15

我刚刚遇到了同样的问题。将 include_directories() 中的路径从绝对路径更改为相对路径后,它添加了适当的依赖项。

看起来 CMake 试图猜测哪些标头是系统的,哪些是与项目相关的。我怀疑以 / 开头的目录作为 -isystem /some/path 传递,因此不会出现在生成的依赖项中。

如果您无法将 ${FOO_SOURCE_DIR} 替换为相对路径,您可以尝试使用适当的 CMake 函数来计算相对路径。 IE:

file(RELATIVE_PATH FOO_SOURCE_REL_DIR
     ${CMAKE_CURRENT_SOURCE_DIR}
     ${FOO_SOURCE_DIR}/.)
include_directories(${FOO_SOURCE_REL_DIR}/include)

I just hit the same issue. After changing paths in include_directories() from absolute to relative it added appropriate dependencies.

Looks like CMake tries to guess which headers are system and which are project related. I suspect that directories that starts with / passed as -isystem /some/path and thus are not presented in generated dependencies.

If you can't replace ${FOO_SOURCE_DIR} with relative path you can try to calculate relative path using appropriate CMake functions. I.e.:

file(RELATIVE_PATH FOO_SOURCE_REL_DIR
     ${CMAKE_CURRENT_SOURCE_DIR}
     ${FOO_SOURCE_DIR}/.)
include_directories(${FOO_SOURCE_REL_DIR}/include)
情定在深秋 2024-12-12 04:55:15

您是否在将包含内容添加到 cpp 文件之前或之后运行了 cmake?

我遇到了这个问题并重新运行 cmake 修复了它。我添加了 include post-cmake.

Did you run cmake before or after adding the includes to your cpp files?

I ran into this problem and re-running cmake fixed it. I'd added the include post-cmake.

倾其所爱 2024-12-12 04:55:15

显然,cmake 从依赖树中删除了系统包含路径(感谢@ony 的提示)。这在大多数情况下可能是有意义的,但有时 cmake 不知道编译器认为什么是系统路径。我们正在使用忽略 /usr/include 的自定义 gcc 构建,但 cmake 认为它不会忽略它。要强制 cmake 将 /usr/include 设为未优化的依赖项,请尝试以下技巧:在路径前面添加 /.

我试图使所有库依赖项都使用 cmake 依赖项功能,包括某些“第 3 方”库,这些库默认情况下并不总是安装在 Linux 上,甚至不可用。例如,Z-lib 压缩。

如果 Z lib 包含文件不在 /usr/include 中,则以下接口目标可以正常工作,但如果在 /usr/include 中,则会中断。

find_package(ZLIB REQUIRED)
message(status "found zlib ${ZLIB_LIBRARIES}")
message(status "found zlib includes ${ZLIB_INCLUDE_DIRS}")
target_link_libraries(zlib_target INTERFACE ${ZLIB_LIBRARIES})
target_include_directories(zlib_target INTERFACE ${ZLIB_INCLUDE_DIRS})

我将最后一行更改为

target_include_directories(zlib_target INTERFACE /.${ZLIB_INCLUDE_DIRS})

并且有效。现在,依赖于 zlib_target 的目标将在编译期间自动获取 -I/./usr/include

Apparently cmake removes system include paths from the dependency trees (thank you @ony for this hint). This probably makes sense most of the time, but sometimes cmake doesn't know what the compiler thinks is a system path or not. We are using a custom gcc build that ignores /usr/include, but cmake thinks it doesn't ignore it. To force cmake to make /usr/include a dependency that is NOT optimized away, try this trick: prepend /. to the path.

I am trying to make all of the library dependencies use the cmake dependency feature, including certain "3rd" party libraries that are not always installed by default on Linux or even available. For example, Z-lib compression.

The following interface target worked fine if the Z lib includes were not in /usr/include, but would break if they were.

find_package(ZLIB REQUIRED)
message(status "found zlib ${ZLIB_LIBRARIES}")
message(status "found zlib includes ${ZLIB_INCLUDE_DIRS}")
target_link_libraries(zlib_target INTERFACE ${ZLIB_LIBRARIES})
target_include_directories(zlib_target INTERFACE ${ZLIB_INCLUDE_DIRS})

I changed the last line to

target_include_directories(zlib_target INTERFACE /.${ZLIB_INCLUDE_DIRS})

and it worked. Now targets that depended on zlib_target would automatically get -I/./usr/include during compilation.

〃温暖了心ぐ 2024-12-12 04:55:15

确保缺少标头的包含语句位于第一个程序指令之前。就我而言, cmake dependent.make 不包含头文件,因为它遵循第一条程序指令。

Make sure that the include statement for the missing header is placed before the first program instruction. In my case cmake depend.make was not including the header file, because it was following the first program instruction.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文