Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 生成可能更新或不更新的源文件_C++_Cmake_Code Generation - Fatal编程技术网

C++ 生成可能更新或不更新的源文件

C++ 生成可能更新或不更新的源文件,c++,cmake,code-generation,C++,Cmake,Code Generation,我有一个CMakeLists.txt,我想在其中生成几个源文件(即versiondata.cpp和version.rc.inc,包括在res.rc)这取决于一般环境(当前git头,gcc-v输出,CMakeCache.txt本身,等等) 如果它仅仅依赖于一些文件,我将使用带有相关DEPENDS和OUTPUT子句的add_custom_命令指令生成它;然而,要精确定位它的文件依赖关系有点棘手;理想情况下,我希望在每次调用make时运行脚本,仅在需要时更新文件;如果生成的文件实际上已被触碰,则应重新

我有一个CMakeLists.txt,我想在其中生成几个源文件(即
versiondata.cpp
version.rc.inc
,包括在
res.rc
)这取决于一般环境(当前git头,
gcc-v
输出,
CMakeCache.txt
本身,等等)

如果它仅仅依赖于一些文件,我将使用带有相关
DEPENDS
OUTPUT
子句的
add_custom_命令
指令生成它;然而,要精确定位它的文件依赖关系有点棘手;理想情况下,我希望在每次调用
make
时运行脚本,仅在需要时更新文件;如果生成的文件实际上已被触碰,则应重新生成依赖于它们的目标(如果这些文件的内容与以前相同,则脚本小心不要覆盖这些文件)

我的第一次尝试是使用带有假主输出的
add_custom_命令
,如下所示:

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
从未真正生成,因此始终运行自定义命令。这工作正常,但总是重新生成我的可执行文件,因为CMake由于某些原因会自动接触输出文件(如果生成),即使我的脚本不处理它们

然后我想我可以使用一个自动“从未满足”的
add\u custom\u target
,让它工作起来:

这里的想法是,
versiondata
目标应该从依赖其
副产品的目标中“拉入”,并且应该始终执行。这似乎适用于CMake 3.20,而且
副产品
似乎有一些效果,因为如果我从
我的可执行文件
中删除依赖项,我的脚本就不会被调用

然而,在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中,有两种类型的依赖关系:

  • 目标级相关性,在目标之间

    只有在无条件构建目标所依赖的所有目标后,才能构建目标

  • 文件级相关性,在文件之间

    如果某个文件比它的某个依赖项旧,则将使用相应的
    命令
    重新生成该文件

  • 关键因素是,在建立相关的目标之后,严格执行对相关文件的时间戳的检查

    要正确地重新生成
    versiondata.cpp
    文件和基于该文件的可执行文件,需要两个依赖项:

  • 目标级别,这将确保
    versiondata
    自定义目标 将在可执行文件之前生成

    add_dependencies(my_executable versiondata)
    
  • 文件级,这将确保在任何时候都重新生成可执行文件 将更新文件
    versiondata.cpp

    通过列出
    versiondata.cpp
    在可执行文件的源代码中

    add_dependencies(my_executable versiondata)
    

  • 现在谈谈副产品

    即使没有明确的
    添加依赖项
    ,您的代码也可以在CMake 3.20上运行,因为副产品会自动生成所需的目标级依赖项

    这可以从中的
    dependens
    选项的描述中推断出来:

    在版本3.16中更改:如果任何依赖项是同一目录中某个目标或其任何生成事件的副产品,则会添加目标级依赖项,以确保在生成此目标之前副产品可用

    注意,
    add_executable
    有效地依赖于它的每个源文件

    因为给定的依赖项注释仅适用于CMake 3.16及更高版本,
    在较旧的CMake版本中,副产品不会自动创建目标级别的依赖关系,需要求助于显式的
    add_dependencies

    “我怀疑这在3.20中起作用只是偶然”——不,这种行为是完美的:因为CMake 3.16依赖于副产品会生成目标级别的依赖关系。在您的例子中,这是可执行目标
    my_executable
    和自定义目标
    versiondata
    之间的依赖关系。您可以通过
    add_dependencies(my_executable versiondata)
    明确指定此依赖项,因此即使在CMake 3.16之前版本中,该构建也可以工作。与版本3兼容绝对没有任何好处。5@Tsyvarev如果是真的,很高兴知道这一点,尽管我不会说这是“完美的记录”:我想您引用的部分位于
    添加自定义目标
    依赖
    部分下,正如本文所述,该部分适用于依赖于副产品的自定义目标,而不是其他类型的目标。如果这适用于一般目标,则应在IMO的副产品下。因此,明确的添加依赖项是3.16之前CMake的唯一方法?我很困惑,虽然有了CMake,我真的不应该这么做。@AlexReinking:而且,虽然我们已经做到了,但使用CMake代替一些更好的替代品也绝对没有什么好处,但我们现在就到了。有时有复杂的约束,你必须选择较小的邪恶,如果我特意测试一个特定的较旧的CMake版本,这可能就是其中之一。任何说你必须使用过时的CMake版本的约束都是假的,而且有点受虐狂。你走得越远,你就越会遇到像这样的荒谬问题,基本的事情没有按它们应该的方式工作,你浪费时间解决你根本不应该遇到的“问题”。