add_custom_command - 通过重建更新依赖关系列表

时间:2015-04-21 22:44:46

标签: cmake add-custom-command

查看上次状态更新

初始条件

  • 生成一组c ++源代码生成器,将一个输入文件作为参数
  • 输入文件可能包含其他输入文件
  • 已经解决了获取输出文件列表的任务,解析输入的codegen文件以获取codegen输入的完整列表。  即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文件" a.c"。因为它可以#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 page)一旦准备好(1-3天内),没有我的项目细节。

2 个答案:

答案 0 :(得分:1)

您能说明如何初始化变量codegenInputFiles吗?您可以在那里使用file(GLOB ... )file(GLOB_RECURSE ... )命令。 请参阅documentation

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

在澄清问题后,您应该能够使用IMPLICIT_DEPENDS代替DEPENDS找到解决方法。限制:

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

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

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

    结构:

    .
    ├── 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 (请注意,b.h尚不存在)

    #include "b.h"
    
    int main () {
    }
    

    <强> ./子项目/的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
    

    (虽然每次都会写入文件b.h,导致重新编译a.cpp)

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

    如果您需要进一步澄清,请与我们联系。

答案 1 :(得分:0)

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

  

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

努力工作(我们付出的代价)是让${codegenInputFiles}保持最新状态(导致整个项目重建)。无论如何,如果有人创建了一个新的源文件并且没有将其添加到${codegenInputFiles},你会遇到类似的问题,对吗?所以我认为对包含文件的额外依赖应该被视为相同。