5

查看上次状态更新

初始状态

  • 生成一组以一个输入文件为参数的 c++ 源代码的代码生成器
  • 输入文件可能包含其他输入文件
  • 已经解决了获取输出文件列表、解析输入代码生成文件以获得完整的代码生成输入列表的任务。即 add_custom_command 首次提供了正确的依赖集:

    add_custom_command(OUTPUT ${generatedSources}
                       COMMAND ${codegenCommand} ARGS ${codegenArgs}
                       DEPENDS ${codegenInputFiles})
    

问题场景

  • 当前系统运行良好,直到有人修改 codegen 输入文件之一以包含新输入文件或删除现有输入文件的包含。这种情况下,需要更新提供给 add_custom_command 作为依赖项的 codegen 输入文件列表,但我不知道如何

什么不见​​了

  • 通过项目重建更新 add_custom_command 依赖项的能力

有没有办法在不进行完整项目重建的情况下解决它?

更新 - 替代(更好?)问题描述

我在 cmake 邮件列表上发现了类似的未回答问题,为了更清楚起见,将其发布在这里:http: //article.gmane.org/gmane.comp.programming.tools.cmake.user/52279

我试图让代码生成工具在依赖项方面表现得与 C 源文件“相同”。我的意思是,假设你有一个 C 文件“ac”。因为它可以#include 文件,所以每次内容a.c变化时,它的依赖关系也可能发生变化。使用 -MMD 重新扫描依赖项。我想要一些方法来模拟我的代码生成器。首先我尝试了 add_custom_command,它采用一个固定的 DEPENDS 列表,在定义自定义命令时确定。具体来说,我的意思是这样的:

function(add_generated_library)
   figure_out_dependencies(deps ${ARGN})
   add_custom_command(... DEPENDS ${deps})
endfunction()

但这仅在构建系统生成时捕获依赖关系。每次自定义命令运行时,可能需要更改 DEPENDS 列表,因为更改可能意味着新的依赖项。我应该如何执行此操作?

更新 2 - 可能的解决方案

以下我认为是事实 - 网络上有关于 cmake 支持动态依赖项的声音,这是平滑集成许多非平凡代码生成工具所必需的 - 没有现成可用的最佳解决方案,正如我们所说的那样实际上需要钩子来添加对自定义 DSL 的支持到 IMPLICIT_DEPENDS

从cmake手册:

IMPLICIT_DEPENDS 选项请求扫描输入文件的隐式依赖项。给定的语言指定了应该使用其对应的依赖扫描程序的编程语言。目前仅支持 C 和 CXX 语言扫描程序。必须为 IMPLICIT_DEPENDS 列表中的每个文件指定语言。从扫描中发现的依赖关系会在构建时添加到自定义命令的依赖关系中

以下解决方案(希望)符合以下标准:

  • 避免在重建时进行不必要的依赖扫描
  • 避免在重建时运行不必要的代码生成器
  • 允许向客户提供 cmake 函数来注册他们的模型并从该代码生成代码/创建库,而不强加任何项目结构要求(即没有负责代码生成的子项目,模型使用项目特定的策略分布在项目层次结构中)

解决方案思路

无法注册自定义语言扫描器,但可以重用现有的。这个想法是自定义模型文件的依赖关系/层次结构反映为“C”头文件的层次结构。每个层次结构节点在模型文件注册时添加,C 文件包含匹配模型文件包含。如果模型文件包含被更改,C 文件包含被更改。因此,每个 codegen 调用将仅依赖于一个生成的反映传递模型的 C 标头。每个反映的文件都将依赖于模型文件并涉及模型文件的更改。

总结:可能,我的措辞在这一点上不是很清楚,但关于其他人的需求和社区帮助我调查这个问题,我将发布通用解决方案(+链接到 github 或新的 cmake wiki 页面)没有我准备好后的项目细节(1-3 天内)。

4

2 回答 2

2

你能展示你如何初始化变量codegenInputFiles吗?您可能可以在那里使用file(GLOB ... )orfile(GLOB_RECURSE ... )命令。请参阅文档

但请注意,您必须重新运行 cmake 才能生成命令。你在使用 git 吗?然后你可以有一个钩子,每次你拉动时都会强制调用一个 cmake (这样如果有人修改了codegenInputFiles你的自动生成的文件将被更新)。


澄清问题后,您应该能够通过使用IMPLICIT_DEPENDS而不是DEPENDS. 限制:

  1. 它只有在您的输入文件是 C/C++ 时才有效(检查语法,因为您必须为每个指定的文件指定语言)
  2. 您可能需要检查您的 cmake 版本是否支持该命令,即使它看起来已经存在了一段时间
  3. 它仅支持 Makefile 生成器,这听起来很糟糕......

编辑

经过一些迭代,我终于明白了你的问题是什么。我提出以下解决方案:在单独的 cmake 子项目中分离文件生成。当您将构建您的主项目(通过调用 make)时,您将为您的子项目触发 cmake 和 make。调用 cmake 是保持更新依赖项所必需的,同时调用 make 来实际构建您的自动生成的源。

这里我展示了一个项目和一个子项目的示例,项目为子项目调用 cmake 和 make。

结构:

.
├── CMakeLists.txt
├── a.cpp
├── build
└── subProject
    └── CMakeLists.txt

文件内容

./CMakeLists.txt

cmake_minimum_required(VERSION 2.8)

add_custom_target(subProjectTarget ALL)
add_custom_command(TARGET subProjectTarget PRE_BUILD COMMAND mkdir -p ${CMAKE_BINARY_DIR}/subProject && cd ${CMAKE_BINARY_DIR}/subProject && ${CMAKE_COMMAND} ${CMAKE_SOURCE_DIR}/subProject && make)

include_directories(${CMAKE_BINARY_DIR}/subProject)
add_executable (dummy a.cpp)
add_dependencies (dummy subProjectTarget)

./a.cpp(注意 bh 还不存在)

#include "b.h"

int main () {
}

./SubProject/CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
file(WRITE ${CMAKE_BINARY_DIR}/b.h "//I am a dummy file\n")

构建项目(使用默认值make

me@here:~/example/build$ cmake ..
-- The C compiler identification is GNU 4.8.2
-- The CXX compiler identification is GNU 4.8.2
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/me/example/build

me@here:~/example/build$ make
Scanning dependencies of target subProjectTarget
-- The C compiler identification is GNU 4.8.2
-- The CXX compiler identification is GNU 4.8.2
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/me/example/build/subProject
[  0%] Built target subProjectTarget
Scanning dependencies of target dummy
[100%] Building CXX object CMakeFiles/dummy.dir/a.cpp.o
Linking CXX executable dummy
[100%] Built target dummy

请注意,第二次 cmake 调用是在子项目上。

在下一次通话中,一切都变得更快:

me@here:~/example/build$ make
-- Configuring done
-- Generating done
-- Build files have been written to: /home/me/example/build/subProject
[  0%] Built target subProjectTarget
Scanning dependencies of target dummy
[100%] Building CXX object CMakeFiles/dummy.dir/a.cpp.o
Linking CXX executable dummy
[100%] Built target dummy

(虽然这里每次都会写入文件 bh 导致重新编译 a.cpp)

通过使用 cmake 命令生成输出目录(而不是 mkdir)并级联为主项目选择的生成器(这里我假设一切都使用 make),可以大大改进这个存根

如果您需要任何进一步的说明,请告诉我。

于 2015-04-22T22:22:11.217 回答
0

我认为${codegenInputFiles}应该包含硬编码源文件的列表并包含自定义命令所需的文件。文件(GLOB ...)的文档状态:

我们不建议使用 GLOB 从源代码树中收集源文件列表。如果添加或删除源时没有 CMakeLists.txt 文件更改,则生成的构建系统无法知道何时要求 CMake 重新生成。

艰苦的工作(我们得到报酬)是保持${codegenInputFiles}最新(导致整个项目重建)。无论如何,如果有人创建了一个新的源文件并且没有将其添加到${codegenInputFiles}. 所以我相信对包含文件的额外依赖应该被同等对待。

于 2015-04-23T07:46:47.183 回答