Reputation: 73
Iam using CMake together with ninja to build a library. The library is depending on some code which may be generated before-hand by a custom command. The source for this code is within the source-tree and it must stay there, I have no freedom here.
Here's my CMake code:
add_library(some_lib some_source.c)
#some_source.c may be modified by the following custom command
add_custom_command(
COMMAND codegen.exe -i some_input.xml
COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_BINARY_DIR}/generated"
OUTPUT ${CMAKE_BINARY_DIR}/generated
DEPENDS some_input.xml
COMMENT "Generating code ..."
)
add_custom_target(generate_something DEPENDS ${CMAKE_BINARY_DIR}/generated)
add_dependencies(some_lib generate_something)
Now if some_input.xml is changed I want to also rebuild some_lib. However in practice this code doesnt seem to work, the command is executed but after it is executed some_lib is not beeing rebuild, though the timestamps of the output files (some_source.c) of the custom command are newer than the library.
Can someone give me a hint on what am I doing wrong or how I can achieve this? Or is there a problem with CMake and ninja?
Thanks in advance, if you need more information please let me know.
Steve
[edit:] It seems to be caused by the generator tool, when I use the BYPRODUCTS option of add_custom_command and replace the generator tool invocation by a cmake -E touch command on some_source.c everything works as expected. Can someone give me a hint on how to debug this, why ninja cancels the build after the generator tool has finished?
Thanks, Steve
[edit2] I found the problem, the problem was that the codegen.exe tool was generating not only one source file but several into an output folder. I need to specify all of these potentially modified sources to as "BYPRODUCTS". Than everything works as expected.
Upvotes: 0
Views: 550
Reputation: 356
I dont want CMake to delete the file if a "clean" is executed
BYPRODUCTS
will still be cleaned.
What can be done is to utilize a dependency tracking file like you've shown (the "${CMAKE_BINARY_DIR}/generated"
, I used *.stamp
) and then add the dependency tracking file as an OBJECT_DEPENDS to some_source.c
This only works if some_source.c
is pre-existing. Initial testing had some_source.c
get cleaned if I tried to add the GENERATED property.
cmake_minimum_required(VERSION 3.18)
project(in_source_generated)
add_library(some_lib some_source.c)
#some_source.c may be modified by the following custom command
add_custom_command(
# This is the command that actually generates the in source code file.
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_DIR}/some_input.c ${CMAKE_CURRENT_LIST_DIR}/some_source.c
# This command generates a stamp file which is used as the dependency
# tracking
COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_BINARY_DIR}/some_source.stamp"
OUTPUT ${CMAKE_BINARY_DIR}/some_source.stamp
DEPENDS some_input.c
COMMENT "Generating code ..."
)
add_custom_target(generate_something DEPENDS ${CMAKE_BINARY_DIR}/some_source.stamp)
add_dependencies(some_lib generate_something)
set_source_files_properties(some_source.c PROPERTIES OBJECT_DEPENDS ${CMAKE_BINARY_DIR}/some_source.stamp)
add_executable(main main.c)
target_link_libraries(main PRIVATE some_lib)
A simple main.c
#include <stdio.h>
int get_value();
int main(int argc, char *argv[]) {
printf("The value is %d.", get_value());
}
some_source.c
and some_input.c
have the same content. Just toggled the return value in some_input.c
to test out.
int get_value(){
return 4;
}
Upvotes: 1