没有CMake更改时重建配置文件

时间:2018-04-30 14:44:39

标签: cmake

我有一个包含配置文件的项目。

configure_file(version.h.in version/version.h)

相同的代码库在一天内用于多次构建,而不需要在构建之间进行清理。 version.h文件将在第一次运行构建时构建,但后续构建将不会在version.h中重建(并更新修订号)。

有没有办法可以强制CMake始终重建version.h而不管更改,或者更好的是基于subversion版本号的更改(或更改)?

2 个答案:

答案 0 :(得分:2)

要完成这项工作,您需要克服一些问题。

  • 当运行cmake时,您从subversion中提取的任何版本信息都会被生成构建文件,因此变为静态。
  • 只有在检测到生成的构建文件已过期时才会重新运行Cmake(例如:如果CMakeLists.txt文件已更新)
  • 您可以创建一个custom_target,每次构建时都会生成"The target has no output file and is ALWAYS CONSIDERED OUT OF DATE"(来自生成该文件的docsadd_library(version STATIC ${CMAKE_CURRENT_BINARY_DIR}/version_gen.cc) ),但这会强制您重建生成的版本每次文件

这是一种克服上述所有障碍的方法:

首先,创建一个包含已编译版本信息的库。

custom_target

现在,在库和名为gen_version

add_dependencies(version gen_version) 之间添加人工依赖关系
gen_version

这会强制version在构建custom_target库之前运行

现在创建一个名为gen_version的{​​{1}},它将生成版本信息:

add_custom_target(
    gen_version
    ALL
    COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/gen_version.cmake)

此自定义目标已添加到ALL目标,并将在您构建的每时间运行。它将执行另一个名为gen_version.cmake

的cmake脚本

这是第一招。我们得到cmake来执行一个子进程并在每个构建上运行一个新的cmake脚本,其中每个构建都会重新计算所需的版本信息。

下一个技巧是使用临时输出文件调用configure_file仅在必要时更新实际版本文件。这样可以防止在版本没有更改时重新编译。

在下面的示例中,我展示了从git获取版本信息 - 您可以将其替换为您的subversion方法。

<强> gen_version.cmake

# obtain the git version
execute_process(
    OUTPUT_VARIABLE   ${VERSION}
    COMMAND           git rev-parse --short HEAD
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
    )

# configure the version file, but output to a temporary location
configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/version_gen.in
    ${CMAKE_CURRENT_BINARY_DIR}/version_gen.cc.tmp
    )

# compare with the real version file
execute_process(
    COMMAND
        ${CMAKE_COMMAND} -E compare_files
            ${CMAKE_CURRENT_BINARY_DIR}/version_gen.cc.tmp
            ${CMAKE_CURRENT_BINARY_DIR}/version_gen.cc
    RESULT_VARIABLE
        VERSION_NEEDS_UPDATING

    OUTPUT_QUIET
    ERROR_QUIET
)

# update the real version file if necessary
if(VERSION_NEEDS_UPDATING)
    execute_process(
        COMMAND
            ${CMAKE_COMMAND} -E copy
                ${CMAKE_CURRENT_BINARY_DIR}/version_gen.cc.tmp
                ${CMAKE_CURRENT_BINARY_DIR}/version_gen.cc
    )
endif()

set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/version_gen.cc
    PROPERTIES GENERATED TRUE)

答案 1 :(得分:0)

对于一个纯粹的CMake解决方案,@ stevelorimer的答案很棒,还有很长的路要走。但是,您也可以查看您的CI系统(如果有的话)和您的RCS。你问:

  

有没有办法可以强制CMake始终重建version.h而不管变化......?

最简单的方法是在构建过程中只touch version.h.in cmake。如果您下次致电version.h,则会重建make。如果您致电(让我们说)version.h,它会重新运行cmake并重建version.h.in

  

......或者更好的是基于颠覆修订号的变化(或没有变化)?

如果您有权访问自己的svn存储库,则可以在您的存储库中添加pre-commit hook,以便在原位修改version.h(甚至function calculate() { document.getElementById("message").innerHTML = "<br>"; var ind = document.getElementById('ind').value; var f1 = document.getElementById('f1').value; var f2 = document.getElementById('f2').value; var f3 = document.getElementById('f3').value; var f4 = document.getElementById('f4').value; var f5 = document.getElementById('f5').value; var freq = [f1, f2, f3, f4, f5]; var xc = []; const pi = 3.14159; var i; for (i = 0; i < 5; i++) { if ((f1 || f2 || f3 || f4 || f5) == 0) { // can replace the condition with f1*f2*f3*f4*f5 == 0 document.getElementById("message").innerHTML = "Zero Frequencies are not permitted. Please reset the form."; break; } xc[i] = 1 / (2 * pi * freq[i] * ind); document.getElementById("message").innerHTML += `xc(${(i + 1)})${xc[i]}Hz<br>`; } }),并将其添加到提交中。虽然可能比CMake解决方案更复杂,但它还具有不使用SVN或CMake来确定修订版本的额外好处,可能允许其他工具来修改版本。