CMake+;带代码生成器的忍者需要两个构建周期 我有一个代码生成器(第三方java可执行文件),它消耗XML输入(不同的第三方API定义)来生成C++头文件,这些文件是我在项目中需要使用的。我不知道结果的头文件名是什么;我只需要看看生成器在其输出目录中产生了什么。实际上,它是50多个文件,并且在更新xml时添加/删除/修改文件名

CMake+;带代码生成器的忍者需要两个构建周期 我有一个代码生成器(第三方java可执行文件),它消耗XML输入(不同的第三方API定义)来生成C++头文件,这些文件是我在项目中需要使用的。我不知道结果的头文件名是什么;我只需要看看生成器在其输出目录中产生了什么。实际上,它是50多个文件,并且在更新xml时添加/删除/修改文件名,cmake,ninja,Cmake,Ninja,我继承了这样的代码,它创建了一个目标生成的库,项目的其他部分可以使用它来添加所需的include目录: add_custom_命令( 输出${CMAKE\u CURRENT\u BINARY\u DIR}/subdir\u并生成 注释“生成C++标题” 预建 依赖于api_definition.xml 命令java ARGS-Doptions.to.the.java.thing=123 ARGS-jar${JAVA_GENERATOR}${CMAKE_SOURCE_DIR}/subdir/api

我继承了这样的代码,它创建了一个目标
生成的库
,项目的其他部分可以使用它来添加所需的include目录:

add_custom_命令(
输出${CMAKE\u CURRENT\u BINARY\u DIR}/subdir\u并生成
注释“生成C++标题”
预建
依赖于api_definition.xml
命令java
ARGS-Doptions.to.the.java.thing=123
ARGS-jar${JAVA_GENERATOR}${CMAKE_SOURCE_DIR}/subdir/api_definition.xml
)
添加自定义目标(生成的存根取决于${CMAKE\u CURRENT\u BINARY\u DIR}/subdir\u和生成的)
添加_库(生成的_库接口)
添加依赖项(生成的库生成的存根)
目标目录(生成的库系统接口${CMAKE\u CURRENT\u BINARY\u DIR})
如果将Make作为我的
-G
选项用于CMake,则生成的系统行为不正确。最初的干净构建很好。典型的增量构建很好。但是如果我
触摸subdir/api_definition.xml
,那么每个后续增量构建都将重新生成头文件,然后重新编译依赖于这些头文件的所有内容,即使我不再触摸xml文件。这很快就会变得令人讨厌

如果我使用忍者作为我的
-G
(我的首选),那么结果系统的行为就不正确,方式也不一样。初始构建很好。典型的增量构建很好。但是如果我触摸subdir/api_definition.xml,那么下一个增量构建将重新生成头文件,但不会重新编译依赖它们的文件。如果在此之后重新运行build命令(
ninja
),那么依赖于头的所有文件都将重新编译,之后一切都将恢复正常

这两种行为都不是“正确的”。我要么一次又一次地编译东西,要么在构建真正完成之前,我必须非常小心地运行两次
ninja

有没有办法让CMake在这里“做正确的事情”

我更喜欢用忍者。我正在使用CMake 3.12.1,但可以升级

额外研究

基于,我一直在尝试使用“时间戳”文件来标记生成的文件上次更改的时间

add_custom_命令(
输出生成时间戳
注释“生成C++标题”
依赖${JAVA_生成器}api_definition.xml
命令java
ARGS-Doptions.to.the.java.thing=123
ARGS-jar${JAVA_GENERATOR}${CMAKE_SOURCE_DIR}/subdir/api_definition.xml
命令touch.timestamp
)
添加自定义目标(生成的存根取决于生成的时间戳)
添加_库(生成的_库接口)
添加依赖项(生成的库生成的存根)
目标目录(生成的库系统接口${CMAKE\u CURRENT\u BINARY\u DIR})

使用Make时,此功能正常工作。它不会总是被重新生成和重新编译卡住。但是对于忍者,它仍然存在需要两次
Ninja
调用才能达到正确状态的问题。如果有人能够解开这个谜团,我真的更愿意选择忍者…

第一个
add\u custom\u命令调用根本不正确,因为它同时使用
OUTPUT
PRE\u BUILD
关键字,而这两个关键字不受支持(请参阅)。第二个
add\u custom\u命令
调用看起来很合理。但是如果没有代码的其他部分(使用这些头),我们只能猜测所描述行为的原因。请准备好。顺便说一句,参考当前源目录,您可以使用
${CMAKE\u current\u source\u DIR}
而不是
${CMAKE\u source\u DIR}/subdir