【问题标题】:Handling header files dependencies with cmake使用 cmake 处理头文件依赖项
【发布时间】:2011-11-19 15:11:48
【问题描述】:

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

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

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

我的项目组织得非常简单:

  • 所有资源所在的顶级目录,主要的 CMakeLists.txt 就在那里
  • 所有公共头文件所在的“包含”目录(在各个子目录中)
  • 一个“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 依赖于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版)

编辑

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

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

是的,就是这样,根本没有引用任何包含:x

【问题讨论】:

  • 了解未正确编译的文件的更多详细信息会很有帮助。 CMake 中的依赖扫描程序当然可以通过包含另一个标题的标题,并正确触发依赖源文件的重新编译。你能分享一个你遇到这种行为的最小例子吗?
  • @Marcus:这很不稳定,我不会在这里倾倒我的项目,有点大问题。从您的回答中,虽然我知道它不应该发生......我忘了准确地说我在 Windows 上,从 MSYS(基于 MinGw)shell 调用,这可能是一个问题吗?另外,我也使用 cmake 在 MSYS 上构建 LLVM/Clang 项目,从未遇到过问题。
  • 听起来可能是 Windows/MSYS 上的依赖扫描程序中的错误。我在那种环境下没有做很多工作,想知道你是否曾经在 Linux/Mac 或 MSVC 项目上看到过与 Unix Makefiles 项目类似的行为。
  • @Marcus:不幸的是,我家里只有 Windows,所以我从来没有在其他环境中看到过它,因为我不使用它们。
  • 您是否也尝试过在set(SUB3_SRCS …) 中列出标题?我一直这样做,没有遇到过这样的问题。

标签: c++ dependencies cmake header-files


【解决方案1】:

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

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

如果 Z 库包含不在 /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

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 啊,谢谢,我搜索了依赖项但找不到它们在哪里,我会检查这个文件。
      • 终于查到了,depend.make 基本上表明 '.obj' 只依赖于生成它的源文件,根本不谈论包含文件。 ...
      【解决方案4】:

      您是在将包含添加到您的 cpp 文件之前还是之后运行 cmake?

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

      【讨论】:

        猜你喜欢
        • 2017-08-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-19
        • 1970-01-01
        相关资源
        最近更新 更多