cmake execute process before anything else - cmake

I've a problem with CMake executing a process before doing anything else.
The following code snippet shows the situation:
if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/generated")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/generated")
execute_process(
# This tool generates library sources, which are not known before
COMMAND "source_file_generator_command"
# This tool iterates over the generated source tree and creates
# a proper CMakeLists.txt in the 'generated' directory from the
# source files found there
COMMAND "cmake_lists_generator_command"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/generated"
)
endif()
# At this point the generated subdirectory (with the also
# generated CMakeLists.txt file) shall be included
add_subdirectory(
"${CMAKE_CURRENT_BINARY_DIR}/generated"
"${CMAKE_CURRENT_BINARY_DIR}/generated_build"
)
# But the 'add_subdirectory' statement fails due to non-existing
# CMakeLists.txt in the 'generated' source directory at this point
The problem is, as commented above, that the CMakeLists.txt file in the subdirectory which should be added is generated on the fly by a special script (the generated sources are not known before) during the first CMake run. Literally, I need CMake to wait until all the statements within the if/else block are executed and process the add_subdirectory statement not until everything is done (the CMakeLists.txt is generated). Is there an adequate solution for such a use case?
Thanks for your help,
Felix

When several COMMANDs for execute_process are used, they are executed in pipe. From the description of this CMake command:
Runs the given sequence of one or more commands with the standard output of each process piped to the standard input of the next.
If you want true sequential execution of the commands, you need to use one call to execute_process per COMMAND:
execute_process(
COMMAND "source_file_generator_command"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/generated"
)
execute_process(
COMMAND "cmake_lists_generator_command"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/generated"
)

Related

CMake: FetchContent interferes with CMAKE_TOOLCHAIN_FILE [duplicate]

It can be a pain to refrence ExternalProjects when their install targets are messed up. So one may want to build and install ExternalProjects once before generating main project files for given project. Is it possible with CMake and how to do it?
You may use cmake call within execute_process for configure and build CMake project, which contains ExternalProject:
other_project/CMakeLists.txt:
project(other_project)
include(ExternalProject)
ExternalProject_Add(<project_name> <options...>)
CMakeLists.txt:
# Configure external project
execute_process(
COMMAND ${CMAKE_COMMAND} ${CMAKE_SOURCE_DIR}/other_project
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/other_project
)
# Build external project
execute_process(
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}/other_project
)
Such a way other_project will be configured and built in directory ${CMAKE_BINARY_DIR}/other_project. If you do not disable installation in ExternalProject_Add call, then it will performed when building other_project.
Normally, you want some options to ExternalProject, like SOURCE_DIR, BINARY_DIR, INSTALL_DIR, to be deduced from variables in the main project. You have two ways for achive that:
Create CMakeLists.txt for other_project with configure_file, called from main project (before execute_process command).
Pass variables from main project as -D parameters to ${CMAKE_COMMAND}.
Having separated execute_process calls for sequential COMMANDS is important. Otherwise, if use single execute_process with several COMMANDS, these commands will be just "piped" (executed concurrently but with output of the first command being treated as input for the second).

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.

CMake call add_subdirectory within custom command

I'm working with a code generator that produces C++ and a CMakeLists.txt file, unfortunately I cannot use this in my main CMakeLists.txt file for testing purposes.
For example you have the following CMakeLists.txt file:
project(SomeProject CXX C)
add_custom_command(OUTPUT ${SRCS}
COMMAND ${CODEGEN_CLI_PATH} -i "${INPUT}" -o "${OUT}"
COMMENT "Generating sources"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
VERBATIM
)
add_custom_target(CODEGEN
DEPENDS
${SRCS}
)
# Needs to be executed after the custom command
add_subdirectory(${GENERATED_CMAKE_LISTS_LOCATION})
Is it possible to use functions such as add_subdirectory only after you execute custom commands for a particular target, such as CODEGEN?
I've already tried to execute it by adding an extra line to the existing custom command:
COMMAND ${CMAKE_COMMAND} -D DIR=${GENERATED_CMAKE_LISTS_LOCATION} -P add_subdirectories.cmake
Unfortuantly this doesn't work because it isn't allowed to execute functions like add_subdirectory in script mode.
Neither I can manage to call custom made functions (that are executing add_subdirectory) from add_custom_command that are located in the same file.
Nope, it is not possible. The add_subdirectory command is run during configuration step, while CODEGEN is a target that runs during build.
You seem to be doing something wrong, so the only advice I can give you is to use execute_process command to run commands you need. The execute_process command is executed during configuration stage, so it will be able to generate files you need before add_subdirectory.
But again, please describe your problem, why do you want CMake to do that.
I have a huge fixed unsigned char array that I compiled into a static library. The way I work around it is by:
if(NOT EXISTS ${PATH_TO_FOLDER}/smeagol.a)
add_subdirectory(smeagol)
endif()
I'm still looking for a nicer kung-fu way to do it using cmake. I feel that its out there, and I will update this answer once i find it.

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.

Run Command after generation step in CMake

I have a command line tool that should be run after CMake created my .sln-file. Is there any way to do that using CMake?
Using execute_process(COMMAND ..) at the end of the CMakeLists.txt does not help because this is executed after the Configure step, however, the .sln-file is created in the generation step.
Thanks a lot!
A rather horrifying way to do it is by calling cmake from cmake and doing the post-generate stuff on the way out of the parent script.
option(RECURSIVE_GENERATE "Recursive call to cmake" OFF)
if(NOT RECURSIVE_GENERATE)
message(STATUS "Recursive generate started")
execute_process(COMMAND ${CMAKE_COMMAND}
-G "${CMAKE_GENERATOR}"
-T "${CMAKE_GENERATOR_TOOLSET}"
-A "${CMAKE_GENERATOR_PLATFORM}"
-DRECURSIVE_GENERATE:BOOL=ON
${CMAKE_SOURCE_DIR})
message(STATUS "Recursive generate done")
# your post-generate steps here
# exit without doing anything else, since it already happened
return()
endif()
# The rest of the script is only processed by the executed cmake, as it
# sees RECURSIVE_GENERATE true
# all your normal configuration, targets, etc go here
This method doesn't work well if you need to invoke cmake with various combinations of command line options like "-DTHIS -DTHAT", but is probably acceptable for many projects. It works fine with the persistently cached variables, including all the cmake compiler detection when they're initially generated.
From the following links, it seems like there is no such command to specify execution after CMake generated .sln files.
https://cmake.org/pipermail/cmake/2010-May/037128.html
https://cmake.org/pipermail/cmake/2013-April/054317.html
https://cmake.org/Bug/view.php?id=15725
An alternative is to write a wrapper script as described in one of the above links.
cmake ..
DoWhatYouWant.exe
Yes, add_custom_command paired with add_custom_target got this covered
http://cmake.org/cmake/help/cmake-2-8-docs.html#command:add_custom_command
http://cmake.org/cmake/help/cmake-2-8-docs.html#command:add_custom_target
For an example take a look at my answer to another question
cmake add_custom_command