[CMake] How to use add_custom_command correctly

Michael Hertling mhertling at online.de
Wed Sep 28 19:46:40 EDT 2011


On 09/28/2011 01:45 PM, Martin Kupke wrote:
> Now it seems to be solved, the generator is called and the generated 
> sources / headers are then compiled and linked into a library.
> 
> My changes are in the
> 
> D:/project/Discovery/Generated/Driver/CMakeLists.txt
> 
> just adding a add_custom_target( MyGeneratedSources ALL DEPENDS 
> ${all_generated_srcs} ${all_generated_hdrs} )
> 
> Additionally I added in the root CMakeLists.txt
> add_dependencies( ${MY_PROJECT} MyGeneratedSources )
> 
> This works fine.

Just two additional remarks:

- For ADD_CUSTOM_COMMAND(OUTPUT ...), it's documented explicitly
that relative paths after the OUTPUT clause will be interpreted
with respect to the current binary directory, so you may leave
out the leading ${CMAKE_CURRENT_BINARY_DIRECTORY} and specify
relative paths here. However, for the DEPENDS clause, there
is no such documentation.

- A custom command's OUTPUTs must be mentioned as other targets'
prerequisites, i.e. as source files in ADD_EXECUTABLE/LIBRARY()
or after the DEPENDS clause of ADD_CUSTOM_TARGET() in the same
CMakeLists.txt file. Otherwise, the rule for the then unused
OUTPUT is dropped, and it will never be generated. Thus, for
generated sources/headers, there should be no need for an
additional custom target as a custom command's anchor.

Regards,

Michael

> On 28.09.11 13:34, Rolf Eike Beer wrote:
>>>
>>> On 27.09.11 18:24, Michael Wild wrote:
>>>> On 09/27/2011 05:59 PM, Martin Kupke wrote:
>>>>> Hi,
>>>>>
>>>>> in my project there is a subfolder which SHALL contain sources to
>>>>> generate a library. The problem is that at startup of the project there
>>>>> are no source files existing, because they will be generated by a code
>>>>> generator. This means within the build process the code generator needs
>>>>> to be called first, then generates the output files in the subfolder
>>>>> and
>>>>> then a library shall be generated from that source files (this are
>>>>> standard .c and .h files). If I start the code generator by hand to
>>>>> generate the source files and remove the custom command, then the
>>>>> compilation is successful, but I want the code generator to be started
>>>>> every time the configuration file for the code generator has changed.
>>>>>
>>>>> In my sample below
>>>>> * the driver.c would be one of the files which the code generator would
>>>>> generate
>>>>> * the variable CodeGen is the executable tool (the code generator
>>>>> himself)
>>>>> * the variable CodeGenParam contains the parameters which are passed to
>>>>> be able to generate without any user interaction
>>>>> * the variable CodeGenConfig is the input file for the code generator
>>>>>
>>>>> This subfolder contains its own CMakeLists.txt with the following
>>>>> settings:
>>>>> ##################### snip #####################
>>>>> project(CANstack C)
>>>>>
>>>>> add_custom_command( OUTPUT driver.c
>>>>>                                              COMMAND ${CodeGen}
>>>>> ${CodeGenParam}
>>>>>                                              DEPENDS ${CodeGenConfig} )
>>>>> )
>>>>>
>>>>> file(GLOB CANstack_srcs "*.c")
>>>>> file(GLOB CANstack_hdrs "*.h")
>>>>>
>>>>> set(lib_name "CANstack")
>>>>> add_library(${lib_name} STATIC ${CANstack_srcs} ${CANstack_hdrs})
>>>>>
>>>>> ##################### snap #####################
>>>>>
>>>>> I don't get it work that the custom command is called and the source
>>>>> files from the code generator are produced.
>>>>>
>>>> A few issues here:
>>>>
>>>> - Never generate output in the source tree, only in the binary tree.
>>>> - Always use absolute paths with add_custom_command().
>>> I use the absolute paths
>>>> - Always list *all* outputs after the OUTPUT argument, otherwise CMake
>>>> won't know that they are generated sources.
>>> I added the list of *all* files which shall be generated
>>>> - Never use file(GLOB ...). It is evil. And breaks in your case. Just
>>>> don't.
>>> I don't use the file(GLOB ...) anymore in this CMakeLists.txt
>>>> Michael
>>>>
>>> In case the generated output files already exist and the dependency file
>>> ${CodeGenConfig} has been touched, then the output will be generated.
>>>
>>> Typically there is from beginning of the project no source file
>>> existing, because the generator needs to be run first. If the output
>>> files are not existing, then I get an error message from CMake:
>>>
>>> ##################### snip #####################
>>>
>>> CMake Error at Generated/CarIF_Appl/CANstack/CMakeLists.txt:31
>>> (add_library):
>>>     Cannot find source file:
>>>
>>>       D:/project/Discovery/Generated/Driver/uart.c
>>>
>>>     Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm
>>> .hpp
>>>     .hxx .in .txx
>>>
>>> ##################### snap #####################
>>>
>>> How do I have to instruct CMake to run the code generator first, so that
>>> the library can be build of that sources?
>> Can you paste the relevant snippet from your new CMakeLists.txt?
>>
>> You can try this first and see if it helps:
>>
>> add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/driver.c
>>                 COMMAND ${CodeGen} {CodeGenParam}
>>                 DEPENDS ${CodeGenConfig} )
>>
>> add_executable(myexe ${CMAKE_CURRENT_BINARY_DIR}/driver.c)
>>
>> Of course you must tell the CodeGen where to put the result, preferably by
>> passing "${CMAKE_CURRENT_BINARY_DIR}/driver.c" as argument (with the
>> quotes, to make paths with spaces work right). If the generator can't
>> handle this you can try to set WORKING_DIRECTORY to
>> ${CMAKE_CURRENT_BINARY_DIR}, passing all other file arguments with
>> absolute paths then.
>>
>> Eike


More information about the CMake mailing list