add_custom_command on xml files - cmake

our system uses some xml files to generate some code. So I've created a custom command to scan and parse these files, and generate stuff as accorded. This is what I did:
file(GLOB BEAN_XML_FILES "../../*.xml")
add_custom_command(TARGET communication PRE_BUILD
COMMAND python
ARGS bean_maker.py --input-directory ${SOURCE_DIR}/docs/beans --output-directory ${SOURCE_DIR}/beans
WORKING_DIRECTORY ${SOURCE_DIR}/tools/bean_maker
COMMENT "Running bean maker..."
DEPENDS ${BEAN_XML_FILES})
The problem is that add_custom_command only runs when I run cmake, even when I modified some xml inside the folder.
How could I do this to run when changes are made to the files?

Use the add_custom_command signature for adding a custom command to produce output files.
add_custom_command(OUTPUT ${GENERATED_SOURCE_FILES}
COMMAND command1 [ARGS] [args1...]
DEPENDS ${BEAN_XML_FILES})
At build time, the command will execute if the generated files are older than the files they depend on.

The issue is that your custom command only runs when the target needs to be compiled. You need to make CMake thing that the target needs to be recompiled each time you modify one of those xml files.
Here are two options:
Set a decadency that always is changing ( system time, incrementing variable )
Create a second custom command that writes out the latest modified time of all the xml files to a file in your build directory. Depend on that file and you should only see your target recompile after an xml file is changed.

Related

CMake custom command always executes

In my CMakeLists.txt, I define a custom target and command:
add_custom_command(
OUTPUT
${CMAKE_CURRENT_SOURCE_DIR}/input.csv
${CMAKE_CURRENT_SOURCE_DIR}/output1.csv
${CMAKE_CURRENT_SOURCE_DIR}/output2.csv
COMMAND python3
${CMAKE_CURRENT_SOURCE_DIR}/tests/genVectors.py)
add_custom_target(TEST_VECTORS
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/input.csv
${CMAKE_CURRENT_SOURCE_DIR}/output1.csv
${CMAKE_CURRENT_SOURCE_DIR}/output2.csv)
add_executable(VectorTest tests/VectorTest.cpp)
add_dependencies(VectorTest TEST_VECTORS)
It always generates new CSV files even though the files exist. I only need to generate the vectors (with genVectors.py python file) if they do not exist. Is that something wrong with my configuration?
The OUTPUT option of add_custom_command does not guarantee that the generated files are placed here; it just tells CMake that the generated files are expected to be placed there. It is likely that your python script is generating files at a relative path, so they are just being placed somewhere in your CMake binary directory (your build folder). So while your files may be generated correctly, your custom target doesn't see them because it is looking in CMAKE_CURRENT_SOURCE_DIR. Thus, the custom target will always trigger the custom command to re-run.
CMake runs add_custom_command from the CMAKE_CURRENT_BINARY_DIR by default, but you can change it to run from CMAKE_CURRENT_SOURCE_DIR by adding the WORKING_DIRECTORY option. This way, the generated files will be placed at the expected location, and achieve your desired behavior. Try something like this:
add_custom_command(
OUTPUT
${CMAKE_CURRENT_SOURCE_DIR}/input.csv
${CMAKE_CURRENT_SOURCE_DIR}/output1.csv
${CMAKE_CURRENT_SOURCE_DIR}/output2.csv
COMMAND python3
${CMAKE_CURRENT_SOURCE_DIR}/tests/genVectors.py
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_custom_target(TEST_VECTORS
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/input.csv
${CMAKE_CURRENT_SOURCE_DIR}/output1.csv
${CMAKE_CURRENT_SOURCE_DIR}/output2.csv)
add_executable(VectorTest tests/VectorTest.cpp)
add_dependencies(VectorTest TEST_VECTORS)
You can try to generate your file at time of configuration(i.e. while calling cmake). By this way it will created only once.
You can remove add_custom_command and use execute_process to create your files.

How do I condition the build of one target on the execution of another target's binary product?

I have a test code for my c project, which is built as part of my cmake project.
In order to run properly, the SW needs an input binary file.
The binary file is created from a designated .json file (which is in the test's directory) using a separate executable which is also part of the same cmake project.
Before the test is run (i.e. when building it) I need the bin-building executable to be built (easy enough with target dependency), but I also need the resulting executable to run with my .json as input.
What cmake functions enable this?
I tried building a custom command with the binary as output, but the test target doesn't know it needs the binary in order to run, can't accept the binary as a source, and a simple "add_dependancy" resulted in errors.
function(create_binary input_json dst_bin)
if (IS_WINDOWS)
set(exe_path ${OUTPUT_BIN_DIR}/BinaryGenerator.exe)
elseif(IS_LINUX)
set(exe_path ${OUTPUT_BIN_DIR}/BinaryGenerator)
endif()
add_custom_command(OUTPUT ${dst_bin}
COMMAND ${exe_path} ${input_json} ${dst_bin}
DEPENDS ${exe_path} ${dst_bin}
COMMENT STATUS "Creating bin file ${dst_bin} from ${input_json}"
)
endfunction(create_binary)
create_binary(InputParams.json ${OUTPUT_BIN_DIR}/InputParams.bin)
add_executable(MySwTest TestFile.cpp TestFile.h)
add_dependencies(${OUTPUT_BIN_DIR}/InputParams.bin)
I expected cmake to place a target dependency between my test target and the bin creator target, and also on the existence of the test's bin file, thus running the custom command in order to create it.
The actual output from cmake is "The dependency target InputParams.bin doesn't exist". I assume this is because "add_dependency" is meant to work only with targets.
Would adding a custom target including my binary solve this?
This is indeed solvable by defining a custom target that depends on the resulting binary.
When adding a custom command, the actual command is only called if the command's OUTPUT file is needed for another target - so if it's a source file, it will be called.
My command's output is a generated binary, and therefore is not a source file for my target.
However, using add_custom_target() I can create a target dependent on said bin file, and create a dependency between the end target and my custom target.
The working code for the above looks like this:
set(PARAMS_NAME InputParams)
set(INPUT_JSON ${PARAMS_NAME}.json)
set(DST_BIN ${PARAMS_NAME}.bin)
if (IS_WINDOWS)
set(EXE_PATH ${OUTPUT_BIN_DIR}/BinaryGenerator.exe)
elseif(IS_LINUX)
set(EXE_PATH ${OUTPUT_BIN_DIR}/BinaryGenerator)
endif()
add_custom_command(OUTPUT ${DST_BIN}
COMMAND ${EXE_PATH} ${INPUT_JSON} ${DST_BIN}
DEPENDS BinaryGenerator ${INPUT_JSON}
COMMENT STATUS "Creating bin file ${DST_BIN} from ${INPUT_JSON}"
)
add_custom_target(${PARAMS_NAME}BinGenerated DEPENDS ${DST_BIN})
add_executable(MySwTest TestFile.cpp TestFile.h)
add_dependencies(MySwTest ${PARAMS_NAME}BinGenerated)
By adding a dependency between MySwTest and my custom target, I ensure that the command generating my binary is called for each build.

CMakeLists.txt - run process, then execute command

I have the following CMakeLists.txt:
cmake_minimum_required(VERSION 3.0.0)
project(FlaAlgoTests)
...
include_directories("../lib")
...
add_executable(
flamenco_algorithms_anomaly_stiction_tests
...
)
The flamenco_algorithms_anomaly_stiction_tests executable generates a .xml file when it is complete.
I would like to run a process (I guess using ADD_CUSTOM_COMMAND?) after this executable is run, which converts that xml file to an html file.
How can I do this?
The short answer is yes; you can use ADD_CUSTOM_COMMAND to first execute your built executable (flamenco_stiction_tests.exe), and second to run the additional process (my_additional_process.exe). Try something like this:
add_custom_command(TARGET flamenco_algorithms_anomaly_stiction_tests POST_BUILD
COMMAND flamenco_stiction_tests.exe
COMMAND my_additional_process.exe my_generated_file.xml
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Debug
COMMENT "Running built executable and additional process..."
)
Per the CMake documentation, these will be executed in order. You may also configure a script to run after the executable is built instead, using a combination of configure_file() and add_custom_command. Guaranteeing your generated file is available for the second process may be easier and safer that way.

Run custom shell script with CMake

I am having the following directory structure:
/CMakeLists.txt
/component-a/CMakeLists.txt
/...
/component-b/CMakeLists.txt
/...
/doc/CMakeLists.txt
/create-doc.sh
The shell script create-doc.sh creates a documentation file (doc.pdf). How can I use CMake to execute this shell script at build time and copy the file doc.pdf to the build directory?
I tried it by using add_custom_command in the CMakeLists.txt file inside the directory doc:
add_custom_command ( OUTPUT doc.pdf
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/create-doc.sh
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/)
Unfortunately the command is never run.
I also tried execute_process:
execute_process ( COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/create-doc.sh
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ )
Now the script is executed during the configuration phase, but not at build time.
You got almost there with add_custom_command. This is indeed the correct way to tell CMake how to generate a file. However, CMake will only run that when something depends on that file.
When, as in your case, the file itself is the end product and is not used any further by subsequent build steps, the usual approach is to create a custom target to drive the relevant custom command(s):
add_custom_target(
BuildDocs ALL
DEPENDS doc.pdf
)
This (custom target driver for custom commands) is a very common idiom in CMake.
You can of course play around with arguments for add_custom_target (e.g. ALL, COMMENT) as it suits you.

How to best handle data files with CMake?

I've got a CMake project that contains code and a few data files (images to be precise).
My directory structure is like this:
src
data
src contains the source code, data the data files. CMake suggests out of source builds, so when I invoke make, I have the executable program, but not the data files, thus I cannot execute the program.
Of course, make install would copy my data files to the required location and make it work, therefore I develop like this right now:
cmake -DCMAKE_INSTALL_DIR=dist
<edit source code>
make install
dist/myprogram.exe
That's okay if I'm working with the command line and an editor, but I recently decided to move to Eclipse CDT. Generating an Eclipse project from CMake works great, but manually executing the install target from Eclipse is not so nice.
How do you people tackle this problem? Does your program have some clever algorithms to try and find its data directory even if it's not where the binary is? Or do you not use out of source builds?
configure_file should solve that problem.
I have a CMakeLists.txt file in my data directory which contains the following:
configure_file(data_file ${CMAKE_CURRENT_BINARY_DIR}/data_file COPYONLY)
This copies the specified file into the build directory when cmake is invoked, so it is available in the same location even in out of source builds.
configure_file does not support directories however while the file command does:
file(COPY assets DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
And if copying the files takes too much time (they are images...) you could make it even better by creating a "custom" data_header.h with configure_file which contains the paths to the data still in your source-directory.
This is what I do: I have a file "global_build_config.h.in" in my source, containing the following:
const char* const global_testdatapath = "#Test_Data_Path#";
and then use configure_file in CMake:
# Assume CMake knows a variable Test_Data_Path, it will be filled in automatically
# in the generated config/Global_Build_Config.h
configure_file( Global_Build_Config.h.in ${CMAKE_BINARY_DIR}/config/Global_Build_Config.h )
# The config directory should be added as a include-searchpath
include_directories( ${CMAKE_BINARY_DIR}/config/ )
I can then #include "Global_Build_Config.h" in my cpp files and refer to the fixed path.
Your question is a bit old, but in case you're still interested (or someone else), I have a similar scenario where I copy testdata for a unit-test target:
add_custom_command( TARGET ${UTEST_EXE_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Copying unit test data.."
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_HOME_DIRECTORY}/utest/testdata ${CMAKE_BINARY_DIR}
)
So the main idea is to use a post-build target, and it is executed after each build. For me, it's not much data, and the filesystem caches it, so I don't feel the copy process at all. You could probably enhance this by copying with copy_if_different. In that case, however, you have to create a list of your image files and write a loop, because the command is file based. With the GLOB command, this shouldn't be hard to do if you need to.