[CMake] copy_if_different on build

Matthew Woehlke matthew.woehlke at kitware.com
Tue Apr 23 13:42:23 EDT 2013


Please keep this on list so that others may contribute/benefit. Thanks.

On 2013-04-23 10:43, Skippy VonDrake wrote:
>> Hmm... yes, I'm not sure if add_dependencies can be used to add a file
>> dependency to a target (the documentation only talks about adding other
>> targets as dependencies).
>>
>> Usually things like configured files are used as source files, i.e. as
>> inputs to add_executable, etc.
>>
>> If for some reason that doesn't work, I believe you can make your executable
>
> Since this config file is not needed for the code to compile, I want to keep it
> separated from the sources list. CMake should be able to accomplish this
> task without adding the file to the sources.
>
>> dependent on a custom target, which in turn depends on the output file from
>> your custom command. IOW:
>>
>> add_custom_command(OUTPUT out DEPENDS in COMMAND stuff)
>> add_executable(exe sources)
>> add_custom_target(exe_config DEPENDS out)
>> add_dependencies(exe exe_config)
>
> So with the example code above this would translate to?:
>    add_executable (${TARGETNAME} 	main.cpp)
>    add_custom_command(OUTPUT "${output}" DEPENDS
>         "${input}" COMMAND ${CMAKE_COMMAND} -E
>         copy_if_different "${input}" "${output}")
>    add_custom_target(exe_config DEPENDS "${output}")
>    add_dependencies(${TARGETNAME} exe_config)
>
> Which results in make error:
>    make[2]: *** No rule to make target `../src/bin/config.cfg', needed
> by `src/CMakeFiles/exe_config'.  Stop.
>
>> If you only have one custom command, you can probably use add_custom_target
>> to run the command instead, i.e.:
>>
>> add_custom_target(exe_config DEPENDS in COMMAND stuff)
>> add_executable(exe sources)
>> add_dependencies(exe exe_config)
>
> With example code this would be?:
>    add_executable (${TARGETNAME} 	main.cpp)
>    add_custom_target(exe_config DEPENDS
>        "${input}" COMMAND ${CMAKE_COMMAND} -E
>         copy_if_different "${input}" "${output}")
>    add_dependencies(${TARGETNAME} exe_config)
>
> This created the same make error above. Am I translating your suggestions into
> the example code erroneously, Matthew?

Hmm... that is odd. I think there may be something else going on in your 
project that is not obvious from the above information. I wrote a quick 
example along the lines of what you show, and it worked fine for me. 
Actual CMakeLists.txt I used is attached. (The foo.c can contain any 
compiling code, and foo.cfg.in can contain anything or even be empty.)

(Apparently a disadvantage of just using add_custom_target is that it 
always runs, regardless of the DEPENDS. Not that this should be a huge 
problem, though.)

Have you tried naming the input/output like 
"${CMAKE_CURRENT_SOURCE_DIR}/name.in" and 
"${CMAKE_CURRENT_BINARY_DIR}/name"? (I didn't do that in the attached 
example because I was lazy (and the example may only work for in-source 
builds as a result), but that is how I would recommend naming the files 
in a real project.)

(Incidentally, this tickles a ninja generator bug in CMake < 2.8.11.)

-- 
Matthew

-------------- next part --------------
project(foo)
cmake_minimum_required(VERSION 2.8)

add_executable(foo foo.c)
if(1) # Just to show doing it both ways
  add_custom_command(
    OUTPUT foo.cfg
    DEPENDS foo.cfg.in
    COMMAND ${CMAKE_COMMAND} -E copy foo.cfg.in foo.cfg
  )
  add_custom_target(foo_config DEPENDS foo.cfg)
else()
  add_custom_target(foo_config
    DEPENDS foo.cfg.in
    COMMAND ${CMAKE_COMMAND} -E copy_if_different foo.cfg.in foo.cfg
  )
endif()
add_dependencies(foo foo_config)


More information about the CMake mailing list