After my program is linked I need to perform some post-processing on it. I added a add_custom_command(TARGET ...
and that worked fine. However, this extra custom command runs a script (that is not generated; it's checked into the codebase), and I want the target to be considered out of date if that script changes so it will be rebuilt properly.
The add_dependencies
rule seems to only work between top-level elements, which this is not (it's just a script), and there's no DEPENDS
element in this form of the add_custom_command
that I can use.
How do I do this?
It's unfortunately a bit convoluted, but you can use add_custom_target
to invoke CMake in script-processing mode via -P
.
You need to use add_custom_target
here since it will always execute, even if everything's up to date.
Having made this decision, we need to have the custom target execute commands which will check for a new version of your post-processing script file (let's call this "my_script" and assume it's in your root dir), and if it's changed cause your dependent target to go out of date.
This would comprise:
- Compare a previous copy of "my_script" to the current "my_script" in the source tree. If the current "my_script" is different, or if the copy doesn't exist (i.e. this is the first run of CMake) then...
- Copy "my_script" from the source tree to the build tree, and...
- Touch a source file of the dependent target so that it goes out of date.
All of the commands required inside the CMake script can be achieved using execute_process
to invoke cmake -E
.
So the CMake script (called e.g. "copy_script.cmake") would be something like:
execute_process(COMMAND ${CMAKE_COMMAND} -E compare_files
${OriginalScript} ${CopiedScript} RESULT_VARIABLE Result)
if(Result)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy
${OriginalScript} ${CopiedScript})
execute_process(COMMAND ${CMAKE_COMMAND} -E touch_nocreate ${FileToTouch})
endif()
The CMake script needs to have required variables passed in via the -D
args before calling -P
, so the calling CMakeLists.txt would have something like:
set(FileToTouch ${CMAKE_SOURCE_DIR}/src/main.cpp)
add_custom_target(CopyScript ALL ${CMAKE_COMMAND}
-DOriginalScript=${CMAKE_SOURCE_DIR}/my_script
-DCopiedScript=${CMAKE_BINARY_DIR}/my_script
-DFileToTouch=${FileToTouch}
-P ${CMAKE_SOURCE_DIR}/copy_script.cmake)
add_executable(MyExe ${FileToTouch})
This will cause a full rebuild of the executable, since it thinks a source file has been modified. If you only require to force relinking there may be a better way to achieve this.