How to change file timestamp from CMake? - cmake

I'm generating .pro files for QtCreator from a CMake script. A file in the project is to be generated later using a QMAKE_EXTRA_COMPILERS instruction (the file is re-generated from other ones using an external tool only if it is older than them).
To make sure the file to be generated is imported in QtCreator project without warning, I need to create it (else QtCreator reports warnings while parsing the .pro file).
To make sure the file gets generated upon first compilation, I need to change the timestamp to be very old (older than any input file used to generate it). This is needed for QMAKE_EXTRA_COMPILERS to consider the file as needing to be re-generated.
To do so, I do:
file(WRITE ${output_file_path} "To be generated..." )
execute_process( COMMAND touch.exe ${output_file_path} -t 0001010101 )
But, the execute_process( COMMAND touch.exe ${output_file_path} -t 0001010101 ) takes a while. I have hundreds of files like that in my project and commenting this execute_process line divides my CMake generation time by 2 (0m45s vs 1m30s). I bet the execution of an external process is slowing things down....
Is there any way to change a file timestamp using pure CMake commands?

cmake builtin commands are the preferred way. You can touch files by using:
execute_process(COMMAND ${CMAKE_COMMAND} -E touch ${output_file_path} -t 0001010101)
This also works in any platform, independent if linux or windows.
If you have 'hundreds of files' you can touch them in one statement by providing touch command with multiple arguments, thus saving time on running make/build system commands (less dependencies to resolve for cmake build system :) .

Related

Rebuild configuration file when there are no CMake changes

I have a project with a configuration file in it.
configure_file(version.h.in version/version.h)
The same code base is used for multiple build in a day, without cleaning between builds. The version.h file will be built the first time the build is run, but subsequent builds will not rebuild (and update the revision number) in the version.h.
Is there a way I can force CMake to always rebuild version.h regardless of changes, or better yet based on a change (or lack of change) in a subversion revision number?
There are a few issues you need to overcome to have this work.
When cmake is run any version information you extract from subversion is baked into the generated build files, and so becomes static.
Cmake is only rerun if it detects the generated build files have become out of date (eg: if a CMakeLists.txt file is updated)
You can create a custom_target which will be run every time you build (from the docs: "The target has no output file and is ALWAYS CONSIDERED OUT OF DATE") which generates the file, but that will force you to rebuild your generated version file every time.
Here is an approach which overcomes all of the above hurdles:
First, create a library which will contain the compiled version information.
add_library(version STATIC ${CMAKE_CURRENT_BINARY_DIR}/version_gen.cc)
Now, add an artificial dependency between the library and a custom_target called gen_version
add_dependencies(version gen_version)
This will force gen_version to be run before building the version library.
Now create a custom_target called gen_version which will generate the version information:
add_custom_target(
gen_version
ALL
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/gen_version.cmake)
This custom target is added to the ALL target, and will be run every time you build. It will execute another cmake script called gen_version.cmake
This is the first trick. We get cmake to execute a subprocess and run a new cmake script on each build, in which the required version information is calculated anew each build.
The next trick is to call configure_file with a temporary output file, and only update the real version file if necessary. This prevents the need to recompile when the version doesn't change.
In the below example I show obtaining the version information from git - you can swap this for your subversion method.
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)
For a pure CMake solution #stevelorimer's answer is great and the way to go. But, you can also look to your CI system (if you have one) and your RCS. You asked:
Is there a way I can force CMake to always rebuild version.h regardless of changes...?
The simplest way is to just touch your version.h.in as part of your build process. If you next call cmake, version.h will be rebuilt. If you call (let's say) make, it will re-run cmake and rebuild version.h.
...or better yet based on a change (or lack of change) in a subversion revision number?
If you have access to your svn repo you can add a pre-commit hook to your repo that modifies version.h.in (or even version.h) in situ, and adds it to the commit. While possibly more complicated than the CMake solution, it has the added benefit of not using SVN or CMake to determine the revision, possibly allowing other tooling to scrape the revision.

In CMake how do I create a file needed at configure time?

Edit: my question targets the early configure stage where CMake input files are still being parsed and thus have to be present before include() is being called. So the answer found here: Force CMake to generate configure_file target every build does not solve my problem since it generates files after include() statements have been interpreted.
I have a CMakeLists.txt that includes a file which is generated in the configure stage:
execute_process(COMMAND "my-generator -o generated.cmake")
include(generated.cmake)
Apart from the fact that this approach doesn't feel right (not to say elegant) I now need to re-generate that file before every build (my-generator produces output that incorporates the current time).
My assumption is that I can't use add_custom_command() or add_custom_target() because the file would be generated at compile time but needed in the configure-step.
This very old post suggests to touch the input file so I did this:
execute_process(
COMMAND "my-generator -o generated.cmake"
COMMAND cmake -E touch "${CMAKE_CURRENT_LIST_FILE}")
.. which does not produce errors but calling make multiple times won't run the configure step more than once.
What do I do wrong? Is there a better approach?

add_custom_command on xml files

our system uses some xml files to generate some code. So I've created a custom command to scan and parse these files, and generate stuff as accorded. This is what I did:
file(GLOB BEAN_XML_FILES "../../*.xml")
add_custom_command(TARGET communication PRE_BUILD
COMMAND python
ARGS bean_maker.py --input-directory ${SOURCE_DIR}/docs/beans --output-directory ${SOURCE_DIR}/beans
WORKING_DIRECTORY ${SOURCE_DIR}/tools/bean_maker
COMMENT "Running bean maker..."
DEPENDS ${BEAN_XML_FILES})
The problem is that add_custom_command only runs when I run cmake, even when I modified some xml inside the folder.
How could I do this to run when changes are made to the files?
Use the add_custom_command signature for adding a custom command to produce output files.
add_custom_command(OUTPUT ${GENERATED_SOURCE_FILES}
COMMAND command1 [ARGS] [args1...]
DEPENDS ${BEAN_XML_FILES})
At build time, the command will execute if the generated files are older than the files they depend on.
The issue is that your custom command only runs when the target needs to be compiled. You need to make CMake thing that the target needs to be recompiled each time you modify one of those xml files.
Here are two options:
Set a decadency that always is changing ( system time, incrementing variable )
Create a second custom command that writes out the latest modified time of all the xml files to a file in your build directory. Depend on that file and you should only see your target recompile after an xml file is changed.

CMake Configure File Build Rule

I'm using CMake for my build system and in the project, we will have a bunch of configuration files. Some of them will just need to be copied over, some will need to be modified per computer. I'm currently using CMake's "configure_file" command to copy/replace parts of the file. This works great, and I love how I can use any variable from CMake in the configure routine.
But if you change the original file, CMake will not pick this up and you have to rerun cmake for it to configure the directory. When I run "make", I want it to pick up that I've changed the file and rerun configure.
It will also reconfigure files always, even if the file it is overwriting is newer. I want it to act like a custom target.
I think I can do this with add_custom_command, but I don't think I can run a CMake command from add_custom_command. So is there anyway to duplicate the behaviour that configure_file does in CMake?
I recently upgraded to CMake 2.8. It seems like it automatically has the exact behavior I wanted.
I do not think this has an easy answer. I see two options:
To trigger a re-run of cmake if an input changes, you might be able to make your input file depend on CMakeLists.txt.
To run a cmake command as part of and add_custom_command, there is the variable ${CMAKE_COMMAND}, which will give you the path to the running cmake. You could, as part of the configure step, generate a fragment of CMake code (that calls configure_file) that is invoked using the -P option. Either pass substitutions on the command line using -D, or write them to the CMake fragment.

How to best handle data files with CMake?

I've got a CMake project that contains code and a few data files (images to be precise).
My directory structure is like this:
src
data
src contains the source code, data the data files. CMake suggests out of source builds, so when I invoke make, I have the executable program, but not the data files, thus I cannot execute the program.
Of course, make install would copy my data files to the required location and make it work, therefore I develop like this right now:
cmake -DCMAKE_INSTALL_DIR=dist
<edit source code>
make install
dist/myprogram.exe
That's okay if I'm working with the command line and an editor, but I recently decided to move to Eclipse CDT. Generating an Eclipse project from CMake works great, but manually executing the install target from Eclipse is not so nice.
How do you people tackle this problem? Does your program have some clever algorithms to try and find its data directory even if it's not where the binary is? Or do you not use out of source builds?
configure_file should solve that problem.
I have a CMakeLists.txt file in my data directory which contains the following:
configure_file(data_file ${CMAKE_CURRENT_BINARY_DIR}/data_file COPYONLY)
This copies the specified file into the build directory when cmake is invoked, so it is available in the same location even in out of source builds.
configure_file does not support directories however while the file command does:
file(COPY assets DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
And if copying the files takes too much time (they are images...) you could make it even better by creating a "custom" data_header.h with configure_file which contains the paths to the data still in your source-directory.
This is what I do: I have a file "global_build_config.h.in" in my source, containing the following:
const char* const global_testdatapath = "#Test_Data_Path#";
and then use configure_file in CMake:
# Assume CMake knows a variable Test_Data_Path, it will be filled in automatically
# in the generated config/Global_Build_Config.h
configure_file( Global_Build_Config.h.in ${CMAKE_BINARY_DIR}/config/Global_Build_Config.h )
# The config directory should be added as a include-searchpath
include_directories( ${CMAKE_BINARY_DIR}/config/ )
I can then #include "Global_Build_Config.h" in my cpp files and refer to the fixed path.
Your question is a bit old, but in case you're still interested (or someone else), I have a similar scenario where I copy testdata for a unit-test target:
add_custom_command( TARGET ${UTEST_EXE_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Copying unit test data.."
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_HOME_DIRECTORY}/utest/testdata ${CMAKE_BINARY_DIR}
)
So the main idea is to use a post-build target, and it is executed after each build. For me, it's not much data, and the filesystem caches it, so I don't feel the copy process at all. You could probably enhance this by copying with copy_if_different. In that case, however, you have to create a list of your image files and write a loop, because the command is file based. With the GLOB command, this shouldn't be hard to do if you need to.