生成可能更新也可能不更新的源文件
Generate a source file that may or may not be updated
我有一个 CMakeLists.txt,我想在其中生成几个源文件(即 versiondata.cpp
和 version.rc.inc
,包含在 res.rc
中),这取决于一般环境(当前 git HEAD,gcc -v
输出,CMakeCache.txt
本身,等等)。
如果它只依赖于某些文件,我会使用带有相关 DEPENDS
和 OUTPUT
子句的 add_custom_command
指令生成它;然而,要准确指出它的 file 依赖关系有点棘手;理想情况下,我希望每次调用 make
时 运行 我的脚本,仅在需要时更新文件;如果生成的文件实际上已被触及,则应重建依赖于它们的目标(如果文件与以前的内容相同,脚本会小心不要覆盖文件)。
我的第一次尝试是使用带有假主输出的 add_custom_command
,如下所示:
add_custom_command(OUTPUT versiondata.cpp.fake versiondata.cpp version.rc.inc
COMMAND my_command my_options
COMMENT "Generating versiondata.cpp"
)
# ...
# explicitly set the dependencies of res.rc, as they are not auto-deduced
set_source_files_properties(res.rc PROPERTIES OBJECT_DEPENDS "${PROJECT_BINARY_DIR}/version.rc.inc;${PROJECT_SOURCE_DIR}/other_stuff.ico")
# ...
add_executable(my_executable WIN32 ALL main.cpp versiondata.cpp res.rc)
versiondata.cpp.fake
从来没有真正生成过,所以自定义命令总是 运行。这工作正常,但总是重建 my_executable
,因为 CMake 出于某些原因自动接触输出文件(如果生成),即使我的脚本让它们单独存在。
然后我想我可以使用自动“从未满足”的 add_custom_target
使其工作:
add_custom_target(versiondata BYPRODUCTS versiondata.cpp version.rc.inc
COMMAND my_command my_options
COMMENT "Generating versiondata.cpp"
)
# ...
# explicitly set the dependencies of res.rc, as they are not auto-deduced
set_source_files_properties(res.rc PROPERTIES OBJECT_DEPENDS "${PROJECT_BINARY_DIR}/version.rc.inc;${PROJECT_SOURCE_DIR}/other_stuff.ico")
# ...
add_executable(my_executable WIN32 ALL main.cpp versiondata.cpp res.rc)
这里的想法是 versiondata
目标应该从依赖于它的 BYPRODUCTS
的目标中“拉入”,并且应该始终执行。这似乎适用于 CMake 3.20,并且 BYPRODUCTS
似乎有一些效果,因为如果我从 my_executable
中删除依赖项,我的脚本就不会被调用。
然而,在 CMake 3.5 上我得到
make[2]: *** No rule to make target 'version.rc.inc', needed by 'CMakeFiles/my_executable.dir/res.rc.res'. Stop.
如果我从 version.rc.inc
中删除显式依赖项,它根本不会生成
[ 45%] Building RC object CMakeFiles/my_executable.dir/res.rc.res
/co/my_executable/res.rc:386:26: fatal error: version.rc.inc: No such file or directory
#include "version.rc.inc"
^
compilation terminated.
/opt/mingw32-dw2/bin/i686-w64-mingw32-windres: preprocessing failed.
CMakeFiles/my_executable.dir/build.make:5080: recipe for target 'CMakeFiles/my_executable.dir/res.rc.res' failed
make[2]: *** [CMakeFiles/my_executable.dir/res.rc.res] Error 1
所以我怀疑这在 3.20 中起作用只是偶然。
长话短说:有没有办法让这个工作如我所愿?
在 CMake 中有两种类型的依赖:
目标级依赖,在目标.
之间
只有在无条件构建它所依赖的所有目标后,才能构建目标。
文件级依赖,在文件之间。
如果某个文件早于其依赖项之一,将使用相应的 COMMAND
.
重新生成该文件
关键因素是检查相关文件的时间戳是严格执行在构建相关目标[后] =67=].
为了正确重新生成 versiondata.cpp
文件和基于它的可执行文件,需要两个依赖项:
目标级别,这将确保versiondata
自定义目标
将在可执行文件之前构建。
add_dependencies(my_executable versiondata)
文件级别,这将确保可执行文件将在任何时候重建
文件 versiondata.cpp
将被更新。
此依赖项是通过列出 versiondata.cpp
自动创建的
在可执行文件的来源中。
现在介绍副产品。
即使没有显式 add_dependencies
,您的代码也可以在 CMake 3.20 上运行,因为 BYPRODUCTS 会自动.
生成所需的目标级依赖项
这可以从 add_custom_target/add_custom_command 中 DEPENDS
选项的描述推导出来:
Changed in version 3.16: A target-level dependency is added if any dependency is a byproduct of a target or any of its build events in the same directory to ensure the byproducts will be available before this target is built.
并指出,add_executable
实际上取决于它的每个源文件。
因为对 DEPENDS 的注释仅适用于 CMake 3.16 及更高版本,
在较旧的 CMake 版本中,BYPRODUCTS 不会自动 创建目标级依赖项,需要求助于显式 add_dependencies
.
我有一个 CMakeLists.txt,我想在其中生成几个源文件(即 versiondata.cpp
和 version.rc.inc
,包含在 res.rc
中),这取决于一般环境(当前 git HEAD,gcc -v
输出,CMakeCache.txt
本身,等等)。
如果它只依赖于某些文件,我会使用带有相关 DEPENDS
和 OUTPUT
子句的 add_custom_command
指令生成它;然而,要准确指出它的 file 依赖关系有点棘手;理想情况下,我希望每次调用 make
时 运行 我的脚本,仅在需要时更新文件;如果生成的文件实际上已被触及,则应重建依赖于它们的目标(如果文件与以前的内容相同,脚本会小心不要覆盖文件)。
我的第一次尝试是使用带有假主输出的 add_custom_command
,如下所示:
add_custom_command(OUTPUT versiondata.cpp.fake versiondata.cpp version.rc.inc
COMMAND my_command my_options
COMMENT "Generating versiondata.cpp"
)
# ...
# explicitly set the dependencies of res.rc, as they are not auto-deduced
set_source_files_properties(res.rc PROPERTIES OBJECT_DEPENDS "${PROJECT_BINARY_DIR}/version.rc.inc;${PROJECT_SOURCE_DIR}/other_stuff.ico")
# ...
add_executable(my_executable WIN32 ALL main.cpp versiondata.cpp res.rc)
versiondata.cpp.fake
从来没有真正生成过,所以自定义命令总是 运行。这工作正常,但总是重建 my_executable
,因为 CMake 出于某些原因自动接触输出文件(如果生成),即使我的脚本让它们单独存在。
然后我想我可以使用自动“从未满足”的 add_custom_target
使其工作:
add_custom_target(versiondata BYPRODUCTS versiondata.cpp version.rc.inc
COMMAND my_command my_options
COMMENT "Generating versiondata.cpp"
)
# ...
# explicitly set the dependencies of res.rc, as they are not auto-deduced
set_source_files_properties(res.rc PROPERTIES OBJECT_DEPENDS "${PROJECT_BINARY_DIR}/version.rc.inc;${PROJECT_SOURCE_DIR}/other_stuff.ico")
# ...
add_executable(my_executable WIN32 ALL main.cpp versiondata.cpp res.rc)
这里的想法是 versiondata
目标应该从依赖于它的 BYPRODUCTS
的目标中“拉入”,并且应该始终执行。这似乎适用于 CMake 3.20,并且 BYPRODUCTS
似乎有一些效果,因为如果我从 my_executable
中删除依赖项,我的脚本就不会被调用。
然而,在 CMake 3.5 上我得到
make[2]: *** No rule to make target 'version.rc.inc', needed by 'CMakeFiles/my_executable.dir/res.rc.res'. Stop.
如果我从 version.rc.inc
中删除显式依赖项,它根本不会生成
[ 45%] Building RC object CMakeFiles/my_executable.dir/res.rc.res
/co/my_executable/res.rc:386:26: fatal error: version.rc.inc: No such file or directory
#include "version.rc.inc"
^
compilation terminated.
/opt/mingw32-dw2/bin/i686-w64-mingw32-windres: preprocessing failed.
CMakeFiles/my_executable.dir/build.make:5080: recipe for target 'CMakeFiles/my_executable.dir/res.rc.res' failed
make[2]: *** [CMakeFiles/my_executable.dir/res.rc.res] Error 1
所以我怀疑这在 3.20 中起作用只是偶然。
长话短说:有没有办法让这个工作如我所愿?
在 CMake 中有两种类型的依赖:
目标级依赖,在目标.
之间只有在无条件构建它所依赖的所有目标后,才能构建目标。
文件级依赖,在文件之间。
如果某个文件早于其依赖项之一,将使用相应的
重新生成该文件COMMAND
.
关键因素是检查相关文件的时间戳是严格执行在构建相关目标[后] =67=].
为了正确重新生成 versiondata.cpp
文件和基于它的可执行文件,需要两个依赖项:
目标级别,这将确保
versiondata
自定义目标 将在可执行文件之前构建。add_dependencies(my_executable versiondata)
文件级别,这将确保可执行文件将在任何时候重建 文件
versiondata.cpp
将被更新。此依赖项是通过列出
versiondata.cpp
自动创建的 在可执行文件的来源中。
现在介绍副产品。
即使没有显式 add_dependencies
,您的代码也可以在 CMake 3.20 上运行,因为 BYPRODUCTS 会自动.
这可以从 add_custom_target/add_custom_command 中 DEPENDS
选项的描述推导出来:
Changed in version 3.16: A target-level dependency is added if any dependency is a byproduct of a target or any of its build events in the same directory to ensure the byproducts will be available before this target is built.
并指出,add_executable
实际上取决于它的每个源文件。
因为对 DEPENDS 的注释仅适用于 CMake 3.16 及更高版本,
在较旧的 CMake 版本中,BYPRODUCTS 不会自动 创建目标级依赖项,需要求助于显式 add_dependencies
.