<div dir="ltr">Hi all,<div><br></div><div>I'm trying to do some build-time configuration, for things like getting revision information into header files, packaging scripts, etc. So I'm using add_custom_command to run cmake scripts that use configure_file to create new files. However, I'm running into an issue that I'm not sure is a bug, or whether I'm just understanding things wrong. </div>
<div><br></div><div>Here's what I'm trying to to do: at build time a script "get_revision.cmake" computes the revision number and writes it to "revision.cmake" using configure_file. I use a dummy output that never gets created, so that it runs on every build. A second add_custom_command calls configure_revision.cmake, which includes the revision.cmake and uses configure_file to create revision.h. Because I use configure_file, which uses CopyFileIfDifferent internally, it should also mean that the second custom command shouldn't run if the revision number is constant (which it always is in this example), and the main.cpp doesn't get recompiled if revision.h doesn't change. </div>
<div><br></div><div>Here's a self-contained minimal example CMakeLists.txt:</div>
<div><br></div><div>--- CMakeLists.txt ---</div><div><br></div><div><div>cmake_minimum_required (VERSION 2.8)</div><div>project (version)</div><div><br></div><div style># define file names</div><div>set(GET_REVISION_CMAKE ${CMAKE_CURRENT_BINARY_DIR}/get_revision.cmake)</div>
<div>set(REVISION_CMAKE ${CMAKE_CURRENT_BINARY_DIR}/revision.cmake)</div><div>set(REVISION_CMAKE_IN ${REVISION_CMAKE}.in)</div><div>set(REVISION_H ${CMAKE_CURRENT_BINARY_DIR}/revision.h)</div><div>set(REVISION_H_IN ${REVISION_H}.in)</div>
<div>set(CONFIGURE_REVISION_H ${CMAKE_CURRENT_BINARY_DIR}/configure_revision.cmake)</div><div>set(SRC ${CMAKE_CURRENT_BINARY_DIR}/main.cpp)</div><div><br></div><div style># create source files</div><div>file(WRITE ${REVISION_CMAKE_IN} </div>
<div> "set(REVISION @REVISION@)")</div>
<div>file(WRITE ${GET_REVISION_CMAKE}</div><div> "set(REVISION 1234)\n"</div><div> "configure_file(${REVISION_CMAKE_IN} ${REVISION_CMAKE} @ONLY)")</div><div>file(WRITE ${REVISION_H_IN} </div><div> "#define REVISION @REVISION@")</div>
<div>file(WRITE ${CONFIGURE_REVISION_H} </div><div> "include(\"${REVISION_CMAKE}\")\n"</div><div> "configure_file(${REVISION_H_IN} ${REVISION_H} @ONLY)"</div><div>)</div><div>file(WRITE ${SRC} </div>
<div> "#include <iostream>\n"</div><div> "#include \"${REVISION_H}\"\n"</div><div> "int main(int argc, char**argv) { \n"</div><div> " std::cout << REVISION << std::endl;\n"</div>
<div> "}")</div><div><br></div><div style># build time configure commands</div><div>add_custom_command(</div><div> OUTPUT ${REVISION_CMAKE} ${REVISION_CMAKE}.alwaysbuild</div><div> COMMAND ${CMAKE_COMMAND} -P ${GET_REVISION_CMAKE}</div>
<div> DEPENDS ${GET_REVISION_CMAKE}</div>
<div> COMMENT "Updating revision info"</div><div>)</div><div>add_custom_command(</div><div> OUTPUT ${REVISION_H}</div><div> COMMAND ${CMAKE_COMMAND} -P ${CONFIGURE_REVISION_H}</div><div> DEPENDS ${REVISION_H_IN} ${REVISION_CMAKE}</div>
<div> COMMENT "Generating revision header"</div><div>)</div><div>add_custom_target(version DEPENDS ${REVISION_H})</div><div>add_executable(version_test ${SRC})</div><div>add_dependencies(version_test version)</div>
<div><br></div><div>--- CMakeLists.txt end ---<br></div></div><div><br></div><div>However, when I try this, the "Generating revision header" command always runs, both on linux (cmake 2.8.7 with make) and windows (cmake 2.8.10.1 with Visual Studio 2008). This is not what I want, but more importantly, not what I would expect. Is this a bug or are my expectations wrong?</div>
<div><br></div><div>Troubleshooting I've tried already: </div><div><br></div><div>On linux, I see that the revision.cmake modification date is always updated, and therefore the second command always runs. If I change the first add_custom_command to use a fake dependency instead of a fake output, like so:<br>
</div><div>--- snippet ---</div><div><div>add_custom_command(</div><div> OUTPUT ${REVISION_CMAKE}.alwaysbuild</div>
<div> COMMAND ${CMAKE_COMMAND} -E echo_append</div><div> COMMENT "(Run always)"</div><div>)</div><div>add_custom_command(</div><div> OUTPUT ${REVISION_CMAKE} </div><div> COMMAND ${CMAKE_COMMAND} -P ${GET_REVISION_CMAKE}</div>
<div> DEPENDS ${GET_REVISION_CMAKE} ${REVISION_CMAKE}.alwaysbuild</div><div> COMMENT "Updating revision info"</div><div>)</div></div><div>--- snippet end ---<br></div><div>oddly enough, the revision.cmake file is no longer touched, as expected, and the header rule is no longer invoked unnecessarily. So somehow, the presence of a fake output file causes the real output file to be touched. It seems to me, though, that it should have worked in the original too. </div>
<div><br></div><div>On the other hand, in Visual Studio, in both cases the modification date of revision.cmake stays the same. However, in both cases, I still see "Generating revision header" on each build, and I don't understand why - if the dependencies of the second command don't change, why is it rerunning? </div>
<div style><br></div><div style>Note that in all cases (linux and windows) the main.cpp is not rebuilt unnecessarily, so the combination of add_custom_command and configure_file works as expected there.</div>
<div><br></div><div>Can anyone explain what is going on here?</div><div><br></div><div>best regards Mark</div></div>