add_custom_command - 通过重建更新依赖关系列表 [英] add_custom_command -- update dependency list over rebuilds

查看:1975
本文介绍了add_custom_command - 通过重建更新依赖关系列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

查看最后状态更新



初始条件


  • 代码生成器生成以一个输入文件为参数的一组c ++源代码

  • 输入文件可能包含其他输入文件

  • 已经解决了获取输出文件列表的任务,解析输入codegen文件以获取codegen输入的完整列表。
    I.e 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列表可能需要更改,因为更改可能意味着新的依赖关系。如何进行此操作?



UPDATE 2 - 可能的解决方案



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



从cmake手册:



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



以下解决方案


$ b 重建
  • 允许向客户提供cmake函数以注册其模型,并且
    从该代码生成代码/创建库,而不强加任何项目结构要求(即没有子项目负责代码生成,模型使用项目特定的策略分布在项目层次结构中)



  • 解决方案



    无法注册自定义语言扫描程序,但可以重复使用现有的扫描程序。想法是自定义模型文件的依赖/层次结构反映为C头文件的层次结构。每个层次结构节点在注册模型文件时添加,C文件包括匹配模型文件包括。如果模型文件包含get更改,C文件包括get更改。因此,每个代码调用将仅依赖于反映传递模型的一个生成的C头文件。每个反射的文件都将依赖于模型文件,并触及模型文件更改。



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

    解决方案

    您可以显示如何初始化变量 codegenInputFiles ?您可以使用文件(GLOB ...)文件(GLOB_RECURSE ...)命令。
    请参见文档



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



    < hr />

    解决问题后,您应该能够使用 IMPLICIT_DEPENDS ,而不是 DEPENDS 。限制:


    1. 只有在输入文件是C / C ++时才能使用(检查语法,因为必须指定每个文件的语言指定)

    2. 您可能需要检查您的cmake版本是否支持该命令,即使它看起来已经有一段时间了。

    3. 支持Makefile生成器,这听起来很不好...






    EDIT



    经过一些重复,我终于得到了你的问题。
    我提出以下解决方案:在单独的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尚不存在)

      #includebh

    int main(){
    }

    ./ Subproject / CMakeLists.txt

      cmake_minimum_required (VERSION 2.8)
    file(WRITE $ {CMAKE_BINARY_DIR} / bh//我是一个虚拟档案\\\

    构建项目(使用默认 make

      me @ here:〜/ example / build $ cmake .. 
    - C编译器标识为GNU 4.8.2
    - CXX编译器标识GNU 4.8.2
    - 检查工作C编译器:/ usr / bin / cc
    - 检查工作C编译器:/ usr / bin / cc - works
    - 检测C编译器ABI info
    - 检测C编译器ABI info - done
    - 检查CXX编译器是否正常:/ usr / bin / c ++
    - 检查CXX编译器是否正常工作:/ usr / bin / c ++ - works
    - 检测CXX编译器ABI信息
    - 检测CXX编译器ABI信息 - 完成
    - 配置完成
    - 生成完成
    - 编译文件已写入:/ home / me / example / build

    me @ here:〜/ example / build $ make
    扫描目标的依赖关系subProjectTarget
    - - C编译器标识是GNU 4.8.2
    - CXX编译器标识是GNU 4.8.2
    - 检查工作C编译器:/ usr / bin / cc
    - 检查对于工作C编译器:/ usr / bin / cc - 工作
    - 检测C编译器ABI信息
    - 检测C编译器ABI信息 - 完成
    - 检查工作CXX编译器: / usr / bin / c ++
    - 检查工作的CXX编译器:/ usr / bin / c ++ - 工作
    - 检测CXX编译器ABI信息
    - 检测CXX编译器ABI信息 - done
    - 配置完成
    - 生成完成
    - 生成文件已写入:/ home / me / example / build / subProject
    [0%] subProjectTarget
    扫描目标虚拟对象的依赖关系
    [100%]构建CXX对象CMakeFiles / dummy.dir / a.cpp.o
    链接CXX可执行文件
    [100%] dummy

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



    在下一次通话时,一切都更快:

     这里:〜/ example / build $ make 
    - 配置完成
    - 生成完成
    - 生成文件已写入:/ home / me / example / build / subProject
    [0%]建立目标subProjectTarget
    扫描目标虚拟的依赖关系
    [100%]构建CXX对象CMakeFiles / dummy.dir / a.cpp.o
    链接CXX可执行文件
    [100%]建立的目标虚拟

    (虽然这里文件bh每次写入.cpp要重新编译)



    通过使用cmake命令生成输出目录(而不是mkdir)和级联​​选择的主生成器项目(这里我假设一切都使用make)



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


    See last status update

    Initial conditions

    • code generator that generates set of c++ sources taking one input file as parameter
    • input file may include other input files
    • already solved task of getting list of output files, parsing input codegen files to get full list of codegen inputs. I.e. add_custom_command is provided with correct set of dependencies for the first time:

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

    Problem scenario

    • current system works well until someone modifies one of codegen input files to include new input file or remove include of existing one. This case, it is required to update list of codegen input file provided to add_custom_command as dependencies, but I have no idea how

    What is missing

    • ability to update add_custom_command dependencies over project rebuilds

    Is there any way to solve it without making full project rebuild ?

    UPDATE - Alternative (better?) problem description

    I`ve found similar not answered question on cmake mailing list, post it here for better clarity: http://article.gmane.org/gmane.comp.programming.tools.cmake.user/52279

    I am trying to get a code generation tool to behave "the same as" a C source file with respect to dependencies. By that I mean, suppose you have a C file "a.c". Because it can #include files, every time the content of a.c changes, its dependencies may have changed also. The dependencies get rescanned with -MMD. I would like some way to emulate this for my code generator. First I tried add_custom_command, which takes a fixed DEPENDS list, determined at the time the custom command is defined. Concretely, I mean something like this:

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

    But that only captures the dependencies at build-system-generation time. Every time the custom command runs, the DEPENDS list may need to change, because the changes may imply new dependencies.How should I go about doing this?

    UPDATE 2 - Possible solution

    Following I consider as facts - there are voices across the web regarding cmake support of dynamic dependencies, which is required for smooth integration of many non-trivial code generation tools - there`s no ready-for-use optimal solution available, as what we actually need is hook to add support of custom DSL to IMPLICIT_DEPENDS

    From cmake manual:

    The IMPLICIT_DEPENDS option requests scanning of implicit dependencies of an input file. The language given specifies the programming language whose corresponding dependency scanner should be used. Currently only C and CXX language scanners are supported. The language has to be specified for every file in the IMPLICIT_DEPENDS list. Dependencies discovered from the scanning are added to those of the custom command at build time.

    Solution below adheres (hopefully) to following criteria:

    • avoid not necessary dependency scanning on rebuild
    • avoid not necessary code generator run on rebuild
    • allow providing cmake functions to clients to register their models and generate code/create libraries from that code, without imposing any project structure requirements (i.e. no sub-project responsible for code generation, models are distributed across project hierarchy using project-specific policy)

    Solution idea

    It is not possible to register custom language scanner, but it is possible to reuse existing one. The idea is that dependencies / hierarchy of custom model files get reflected as hierarchy of "C" header files. Each hierarchy node get added on registering of model file and C file includes match model file includes. If model file includes get changed, C file includes get changed. Therefore, each codegen invocation would depend on just one generated C header reflecting passed model. Each reflected file will have a dependency on the model file and get touched on model file change.

    To sum up : probably, my wording is not that clear at this point, but with respect to other people needs and community helped me to investigate this problem, I will post generic solution (+ link to github or new cmake wiki page) without my project specifics once it is ready (in 1-3 days).

    解决方案

    Can you show how you initialize the variable codegenInputFiles? You can probably use a file(GLOB ... ) or file(GLOB_RECURSE ... ) command there. See documentation.

    Note, though, that you will have to rerun cmake to have your command being generated. Are you working with git? Then you can have a hook that forces a cmake call every time you pull (so that if somebody modified the codegenInputFiles your auto generated files will be updated).


    After clarification of the problem, you should be able to find a workaround by using IMPLICIT_DEPENDS instead of DEPENDS. Limitations:

    1. It can only work if your input file is C/C++ (check the syntax, as you must specify the language for each file specified)
    2. You might need to check your cmake version supports that command, even though it looks that it has been around for a while
    3. It's only supported for Makefile generator, which sounds pretty bad...


    EDIT

    After some iterations, I finally got what is your problem. I propose the following solution: separate the file generation in a separate cmake subproject. When you will build your main project (by calling make), you will trigger both cmake and make for your subproject. Calling cmake is necessary for keeping updated the dependencies, while calling make to actually build your auto-generated sources.

    Here I show an example of a project and a subproject, with the project invoking cmake and make for the subproject.

    Structure:

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

    File content

    ./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 (Note that b.h doesn't exist yet)

    #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")
    

    Building the project (using default 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
    

    Note that the second time the cmake calls is on the subproject.

    At the next call everything is even faster:

    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
    

    (Although here the file b.h is written every time causing a.cpp to be recompiled)

    This stub can be very much improved by using cmake commands to generate the output directories (and not mkdir) and cascading the generator chosen for the main project (here I am assuming everything is using make)

    Let me know if you need any further clarification.

    这篇关于add_custom_command - 通过重建更新依赖关系列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆