Let's say I have two files main.cpp
and generate_header.cpp
. generate_header.cpp
generates a header containing data that main.cpp
needs to run. based on this answer, I can use the following code to run generate_header.cpp
before building main.cpp
:
add_custom_target(run_generate_header
COMMAND generate_header
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "generating header"
)
add_dependencies(main_target run_generate_header)
However, as generating the header's content is slow, I would like to generate the header content only if the header is empty.
To achieve this, I thought about using a preprocessor macro HEADER_GENERATED
, and check_cxx_symbol_exists
to generate the header's content only if the macro is not defined.
check_cxx_symbol_exists(HEADER_GENERATED ${HEADER_PATH} HEADER_GENERATED)
if (NOT HEADER_GENERATED)
add_dependencies(main_target run_generate_header)
endif()
The problem with this approach is that check_cxx_symbol_exists
runs during the configuration stage, not the build stage, so if the header is erased after configuration, it will not be regenerated and the build will fail. Is there a way to check if the header contains data during the build stage? Thanks in advance!
Do not use add_custom_target
for something that is generated. If something is generated, it's add_custom_command(OUTPUT this_is_generated.h
- tell CMake what is generated and where and from what. Usually, you want pairs add_custom_command
& add_custom_target
. Sole add_custom_target
is for executing something, like running a linter or printing file size.
I would like to generate it only if it does not contain data.
So do that. Generate files in cmake current binary dir.
add_custom_command(
COMMENT "generating header"
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/gen/the_generated_header.h
COMMAND
sh -xc
[=[
mkdir -vp "$(dirname "$2")"
if it does contains data; then
"$1" -o "$2"
else
echo > "$2"
fi
]=]
sh
$<TARGET_FILE:generate_header>
${CMAKE_CURRENT_BINARY_DIR}/gen/the_generated_header.h
DEPENDS generate_header
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(run_generate_header DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/gen/the_generated_header.h)
add_dependencies(main_target run_generate_header)
target_include_directries(main_target PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/gen)
however, it is not cross platform
To be crossplatform, you would write the sh
script in cmake. So create a file like:
# script.cmake
# check if the file exists in cmake
execute_process(${ARGV1} -o ${ARGV2})
# etc
Then you would call this cmake script from cmake:
add_custom_command(
COMMAND cmake -P ./script.cmake
$<TARGET_FILE:generate_header>
${CMAKE_CURRENT_BINARY_DIR}/gen/the_generated_header.h
....