[CMake] Still problems with add_custom_command

Michael Hertling mhertling at online.de
Thu Oct 6 21:06:07 EDT 2011


On 10/06/2011 05:40 PM, Martin Kupke wrote:
> Hi,
> 
> in my CMake project I have the need for a custom command that should be 
> processed in case a file is touched...that is the file the custom 
> command depends on. I already use the add_custom_command and 
> add_custom_target CMake instructions in my project, but always for 
> CMakeLists.txt files in subfolders where a static library will be build.
> 
> I think I have a real simple requirement, but I don't get it work up to now.
> In my main project  I have a subfolder with an own CMakeLists.txt file, 
> this subfolder is added to the main project by instruction 
> add_subdirectory( "${CMAKE_CURRENT_SOURCE_DIR}/subfolder" ).
> Within the CMakeLists.txt in the subfolder I want to call a custom 
> command, so I added the following lines:
> message( "My Tool started by custom command / target" )

Use the COMMENT clause of ADD_CUSTOM_COMMAND() instead; in this
way, you will see when the custom command is actually executed.

> add_custom_command( OUTPUT Out.txt
>                      COMMAND tool.exe ${ToolConfig}
>                      DEPENDS ${ToolConfig} )
> add_custom_target( TOOL_CFG_OUT
>                     DEPENDS Out.txt )
> 
> In my main project I added the custom target as dependency in the way:
> add_dependencies( ${PROJECT_NAME} TOOL_CFG_OUT )
> 
> If I start the CMake process generating the Makefile I see the output of 
> my message "My Tool started by custom command / target", but the custom 
> command is never called.
> I would like to have a build configuration that every time the dependend 
> file which is declared in the variable ${ToolConfig} is touched, the 
> command tool.exe is started.
> 
> What am I doing wrong? Do you have a sample for me how to start a custom 
> command every time a file is touched. I don't get it work.
> 
> Thanks in advance,
> Martin...

Indeed, custom commands in subdirectories with results used in higher
directories provide some pitfalls. At first, the following exemplary
CMakeList.txt files model the situation you outlined and do work:

# CMakeLists.txt:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(CUSTOMCOMMAND C)
SET(CMAKE_VERBOSE_MAKEFILE ON)
ADD_SUBDIRECTORY(subdir)
FILE(WRITE ${CMAKE_BINARY_DIR}/main.c "int main(void){return 0;}\n")
SET_SOURCE_FILES_PROPERTIES(
    ${CMAKE_BINARY_DIR}/subdir/f.c PROPERTIES GENERATED TRUE)
ADD_EXECUTABLE(main main.c ${CMAKE_BINARY_DIR}/subdir/f.c)
ADD_DEPENDENCIES(main f)

# subdir/CMakeLists.txt:
FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/f.c.in "void f(void){}\n")
ADD_CUSTOM_COMMAND(
    OUTPUT f.c
    COMMAND ${CMAKE_COMMAND} -E copy f.c.in f.c
    DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/f.c.in
    COMMENT "Generating f.c")
ADD_CUSTOM_TARGET(f DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/f.c)

AFAICS, the crux is the DEPENDS clause of ADD_CUSTOM_COMMAND():
Followed by a relative path, it refers to CMAKE_CURRENT_BINARY_DIR,
but the custom command is attached to the custom target "f", and this
is built in CMAKE_BINARY_DIR without having its prerequisites adapted.
Look into subdir/CMakeFiles/f.dir/build.make; the dependency line of
interest is "subdir/f.c: subdir/f.c.in" which is perfect in CMAKE_
BINARY_DIR. Change the DEPENDS clause to "DEPENDS f.c.in", and the
dependency line becomes "subdir/f.c: ../subdir/f.c.in", i.e. Make's
target (f.c) is relative to CMAKE_BINARY_DIR, but the prerequisite
(f.c.in) is relative to CMAKE_CURRENT_BINARY_DIR, or CMAKE_BINARY_
DIR/subdir. Of course, this can't work and might even be considered
as a CMake bug, but the interpretation of the DEPENDS clause w.r.t.
relative paths isn't documented - as opposed to the OUTPUT clause -
so you should always use full paths here when in doubt.

There's another somewhat subtle pitfall revealed by the above-noted
example: During the inital configuration, ADD_EXECUTABLE() searches
${CMAKE_BINARY_DIR}/subdir/f.c, doesn't find it because it doesn't
exist yet, but stumbles over the f.c.in template - and is content
since ".in" is a valid suffix. However, an ".in" file is useless
for a C project on *nix, and so it's ignored. This results in the
quite funny situation that f.c is regenerated each time f.c.in is
touched - as you desired - but it's not compiled and, thus, not
incorporated in the main target's executable. That's the reason
for explicitly setting the GENERATED property on f.c what's not
necessary for the OUTPUT files of a custom command in the same
CMakeLists.txt. Change f.c.in's suffix to .template, e.g., and
you will see that the GENERATED property is actually necessary
as the property imposed automatically by ADD_CUSTOM_COMMAND()
is valid in the respective CMakeLists.txt file only; see the
documentation of SET_SOURCE_FILES_PROPERTIES().

'hope that helps. If not, please boil down your problem to a
minimal but self-contained example which demonstrates the
issue and can be posted here for further investigation.

Regards,

Michael


More information about the CMake mailing list