add_custom_command -- 在重建时更新依赖项列表

Kon*_*tin 5 cmake cmake-custom-command

查看上次状态更新

初始条件

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

    add_custom_command(OUTPUT ${generatedSources}
                       COMMAND ${codegenCommand} ARGS ${codegenArgs}
                       DEPENDS ${codegenInputFiles})
    
    Run Code Online (Sandbox Code Playgroud)

问题场景

  • 当前系统运行良好,直到有人修改 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()
Run Code Online (Sandbox Code Playgroud)

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

更新 2 - 可能的解决方案

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

来自cmake手册:

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

下面的解决方案(希望)遵守以下标准:

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

解决思路

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

总结一下:可能,我的措辞目前还不是那么清楚,但考虑到其他人的需求和社区帮助我调查这个问题,我将发布通用解决方案(+链接到 github 或新的 cmake wiki 页面),而无需我的项目细节一旦准备好(1-3 天内)。

Ant*_*nio 2

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

\n\n

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

\n\n
\n\n

澄清问题后,您应该能够通过使用IMPLICIT_DEPENDS而不是找到解决方法DEPENDS。限制:

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

编辑

\n\n

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

\n\n

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

\n\n

结构:

\n\n
.\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 CMakeLists.txt\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 a.cpp\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 build\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 subProject\n    \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 CMakeLists.txt\n
Run Code Online (Sandbox Code Playgroud)\n\n

文件内容

\n\n

./CMakeLists.txt

\n\n
cmake_minimum_required(VERSION 2.8)\n\nadd_custom_target(subProjectTarget ALL)\nadd_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)\n\ninclude_directories(${CMAKE_BINARY_DIR}/subProject)\nadd_executable (dummy a.cpp)\nadd_dependencies (dummy subProjectTarget)\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
#include "b.h"\n\nint main () {\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

./子项目/CMakeLists.txt

\n\n
cmake_minimum_required(VERSION 2.8)\nfile(WRITE ${CMAKE_BINARY_DIR}/b.h "//I am a dummy file\\n")\n
Run Code Online (Sandbox Code Playgroud)\n\n

构建项目(使用默认make

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

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

\n\n

在下一次调用时,一切都会变得更快:

\n\n
me@here:~/example/build$ make\n-- Configuring done\n-- Generating done\n-- Build files have been written to: /home/me/example/build/subProject\n[  0%] Built target subProjectTarget\nScanning dependencies of target dummy\n[100%] Building CXX object CMakeFiles/dummy.dir/a.cpp.o\nLinking CXX executable dummy\n[100%] Built target dummy\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

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

\n\n

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

\n