[prev in list] [next in list] [prev in thread] [next in thread] 

List:       cmake
Subject:    [CMake] Issues with add_custom_command and config_file at build time
From:       Mark Stijnman <mark.stijnman () gmail ! com>
Date:       2013-05-28 15:53:13
Message-ID: CAOzitBLQv=9iGbnLzbMw76v-2yfDrPibdXuYboMmOby79RQ4jw () mail ! gmail ! com
[Download RAW message or body]

[Attachment #2 (multipart/alternative)]


Hi all,

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.

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.

Here's a self-contained minimal example CMakeLists.txt:

--- CMakeLists.txt ---

cmake_minimum_required (VERSION 2.8)
project (version)

# define file names
set(GET_REVISION_CMAKE ${CMAKE_CURRENT_BINARY_DIR}/get_revision.cmake)
set(REVISION_CMAKE ${CMAKE_CURRENT_BINARY_DIR}/revision.cmake)
set(REVISION_CMAKE_IN ${REVISION_CMAKE}.in)
set(REVISION_H ${CMAKE_CURRENT_BINARY_DIR}/revision.h)
set(REVISION_H_IN ${REVISION_H}.in)
set(CONFIGURE_REVISION_H
${CMAKE_CURRENT_BINARY_DIR}/configure_revision.cmake)
set(SRC ${CMAKE_CURRENT_BINARY_DIR}/main.cpp)

# create source files
file(WRITE ${REVISION_CMAKE_IN}
  "set(REVISION @REVISION@)")
file(WRITE ${GET_REVISION_CMAKE}
  "set(REVISION 1234)\n"
  "configure_file(${REVISION_CMAKE_IN} ${REVISION_CMAKE} @ONLY)")
file(WRITE ${REVISION_H_IN}
  "#define REVISION @REVISION@")
file(WRITE ${CONFIGURE_REVISION_H}
  "include(\"${REVISION_CMAKE}\")\n"
  "configure_file(${REVISION_H_IN} ${REVISION_H} @ONLY)"
)
file(WRITE ${SRC}
  "#include <iostream>\n"
  "#include \"${REVISION_H}\"\n"
  "int main(int argc, char**argv) { \n"
  " std::cout << REVISION << std::endl;\n"
  "}")

# build time configure commands
add_custom_command(
  OUTPUT ${REVISION_CMAKE} ${REVISION_CMAKE}.alwaysbuild
  COMMAND ${CMAKE_COMMAND} -P ${GET_REVISION_CMAKE}
  DEPENDS ${GET_REVISION_CMAKE}
  COMMENT "Updating revision info"
)
add_custom_command(
  OUTPUT ${REVISION_H}
  COMMAND ${CMAKE_COMMAND} -P ${CONFIGURE_REVISION_H}
  DEPENDS ${REVISION_H_IN} ${REVISION_CMAKE}
  COMMENT "Generating revision header"
)
add_custom_target(version DEPENDS ${REVISION_H})
add_executable(version_test ${SRC})
add_dependencies(version_test version)

--- CMakeLists.txt end ---

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?

Troubleshooting I've tried already:

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:
--- snippet ---
add_custom_command(
  OUTPUT ${REVISION_CMAKE}.alwaysbuild
  COMMAND ${CMAKE_COMMAND} -E echo_append
  COMMENT "(Run always)"
)
add_custom_command(
  OUTPUT ${REVISION_CMAKE}
  COMMAND ${CMAKE_COMMAND} -P ${GET_REVISION_CMAKE}
  DEPENDS ${GET_REVISION_CMAKE} ${REVISION_CMAKE}.alwaysbuild
  COMMENT "Updating revision info"
)
--- snippet end ---
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.

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?

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.

Can anyone explain what is going on here?

best regards Mark

[Attachment #5 (text/html)]

<div dir="ltr">Hi all,<div><br></div><div>I&#39;m trying to do some build-time \
configuration, for things like getting revision information into header files, \
packaging scripts, etc. So I&#39;m using add_custom_command to run cmake scripts that \
use configure_file to create new files. However, I&#39;m running into an issue that \
I&#39;m not sure is a bug, or whether I&#39;m just understanding things wrong. </div>

<div><br></div><div>Here&#39;s what I&#39;m trying to to do: at build time a script \
&quot;get_revision.cmake&quot; computes the revision number and writes it to \
&quot;revision.cmake&quot; 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&#39;t run if \
the revision number is constant (which it always is in this example), and the \
main.cpp doesn&#39;t get recompiled if revision.h doesn&#39;t change. </div> \
<div><br></div><div>Here&#39;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>  &quot;set(REVISION \
@REVISION@)&quot;)</div> <div>file(WRITE ${GET_REVISION_CMAKE}</div><div>  \
&quot;set(REVISION 1234)\n&quot;</div><div>  \
&quot;configure_file(${REVISION_CMAKE_IN} ${REVISION_CMAKE} \
@ONLY)&quot;)</div><div>file(WRITE ${REVISION_H_IN} </div><div>  &quot;#define \
REVISION @REVISION@&quot;)</div>

<div>file(WRITE ${CONFIGURE_REVISION_H} </div><div>  \
&quot;include(\&quot;${REVISION_CMAKE}\&quot;)\n&quot;</div><div>  \
&quot;configure_file(${REVISION_H_IN} ${REVISION_H} \
@ONLY)&quot;</div><div>)</div><div>file(WRITE ${SRC} </div>

<div>  &quot;#include &lt;iostream&gt;\n&quot;</div><div>  &quot;#include \
\&quot;${REVISION_H}\&quot;\n&quot;</div><div>  &quot;int main(int argc, char**argv) \
{ \n&quot;</div><div>  &quot; std::cout &lt;&lt; REVISION &lt;&lt; \
std::endl;\n&quot;</div>

<div>  &quot;}&quot;)</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 &quot;Updating revision \
info&quot;</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 &quot;Generating revision \
header&quot;</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 &quot;Generating \
revision header&quot; 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&#39;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 &quot;(Run \
always)&quot;</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 &quot;Updating revision info&quot;</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 &quot;Generating revision header&quot; on each build, and I don&#39;t understand \
why - if the dependencies of the second command don&#39;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>



--

Powered by www.kitware.com

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Follow this link to subscribe/unsubscribe:
http://www.cmake.org/mailman/listinfo/cmake

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic