Cmake >= 3.17 - pre build script execution - Soltution? - cmake

In cmake there is custom commands, which can run PRE_BUILD or PRE_LINK or POST_BUILD.
However, on most platforms, except Visual Studio apparently, PRE_BUILD and PRE_LINK are idendical.
There are plenty of posts here about this issue, all stating this fact but noone giving a possible solution to "acutally PRE BUILD do something".
I for example need to run a bash script which will create some headers (c and c++ headers) automatically, and the source depends on them being A.) available and B.) defining certain things.
Is there an alternative to the custom command in cmake? How is it possible to execute something before the cmake process takes over and starts compiling things?
add_custom_command(TARGET ${PROJECT_NAME}
PRE_BUILD <---------------------------------------- THIS IS PRE_LINK unfortunatelly!
COMMAND ../my_bash_script.sh
DEPENDS ${PROJECT_NAME}
VERBATIM
)

Related

Apply editbin in cmake

I'm trying to automatically call editbin with some options from within a cmake script after the executable has been build. So far without any luck.
is there any example for using editbin in cmake?
is there an example for using any executable in cmake after an executable has been build?
You can use add_custom_command for build events, that is, it will be executed each time you build your target.
From the docs:
A POST_BUILD event may be used to post-process a binary after linking. For example, the code:
add_executable(myExe myExe.c)
add_custom_command(
TARGET myExe POST_BUILD
COMMAND someHasher -i "$<TARGET_FILE:myExe>"
-o "$<TARGET_FILE:myExe>.hash"
VERBATIM)
will run someHasher to produce a .hash file next to the executable after linking.
As for VERBATIM:
All arguments to the commands will be escaped properly for the build tool so that the invoked command receives each argument unchanged. Note that one level of escapes is still used by the CMake language processor before add_custom_command even sees the arguments. Use of VERBATIM is recommended as it enables correct behavior. When VERBATIM is not given the behavior is platform specific because there is no protection of tool-specific special characters.
So in your case you first need to find an executble for editbin and then add your command:
add_custom_command(TARGET target_name POST_BUILD
COMMAND "${editbin_exe} $<TARGET_FILE:target_name>")
Where $<TARGET_FILE:target_name> is a generator expression which yields a path to the output binary file of target target_name.

CMake POST_BUILD COMMAND with dependencies

I have target for shared and want it to run command after build ONLY if the Target output file changed, or same for me if build is updating.
In my example command runes every time when I build project, but I need it to run Only if after build Target output file changed
cmake_minimum_required(VERSION 3.21)
project(myexp)
add_library(Example SHARED source.cpp)
set_target_properties(Example PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin$<0:>"
)
add_custom_command(TARGET Example POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:Example> ${CMAKE_CURRENT_SOURCE_DIR}/new
DEPENDS Example
)
DEPENDS doesnt work here
from documentation - add_custom_command
The second signature adds a custom command to a target such as a library or executable.
This is useful for performing an operation before or after building the target.
The command becomes part of the target and will only execute when the target itself is
built.
If the target is already built, the command will not execute.
maybe my understanding of this is wrong
is there a way to Multi-OUTPUT
THANK YOU

CMake: how to make execute_process wait for subdirectory to finish?

Part of my source code is generated by a tool which is also built under our main project with a add_subdirectory. We execute this tool with a execute_process command. Clearly, if the tool is not built before we reach the execute_process statement it will fail.
I use a GLOB (file(GLOB...)) to find the source files generated. I do this because it is not possible to know beforehand how many files are generated, neither their names.
How do I force cmake to wait for the subproject to be compiled before the execute process? I would need something like a DEPENDS property for the execute_process but this option is not available.
# This subproject will source generator the tool
add_subdirectory(generator)
# I need something like: wait_for(generator)
execute_process(COMMAND generator ${CMAKE_SOURCE_DIR}/src)
file(GLOB GeneratedSources ${CMAKE_SOURCE_DIR}/src/*.cpp)
add_executable(mainprject.exe ${ProcessorSourceFiles}
Command execute_process executes its COMMAND immediately, at configuration stage. So it cannot be arranged after the executable is created with add_executable command: that executable will be built only at build stage.
You need to build subproject at configuration stage too. E.g. with
execute_process(COMMAND ${CMAKE_COMMAND}
-S ${CMAKE_SOURCE_DIR}/generator
-B ${CMAKE_BINARY_DIR}/generator
-G ${CMAKE_GENERATOR}
)
execute_process(COMMAND ${CMAKE_COMMAND}
--build ${CMAKE_BINARY_DIR}/generator
)
The first command invokes cmake for configure the 'generator' project, located under ${CMAKE_SOURCE_DIR}/generator directory. With -G option we use for subproject the same CMake generator, as one used for the main project.
The second command builds that project, so it produces generator executable.
After generator executable is created, you may use it for your project:
execute_process(COMMAND ${CMAKE_BINARY_DIR}/generator/<...>/generator ${CMAKE_SOURCE_DIR}/src)
Here you need to pass absolute path to the generator executable as the first parameter to COMMAND: CMake no longer have generator executable target, so it won't substitute its path automatically.
You will need to model this with target dependencies. The tool "generator" should be a cmake target. In that case use add_custom_target instead of execute_process somthing like this:
add_custom_target(generate_sources ALL COMMAND generator ${CMAKE_SOURCE_DIR}/src))
Then add a target dependency to "generator" using add_dependencies:
add_dependencies(generate_sources generator)
This will make sure your target "generate_sources", which runs the tool will only run during build after the target "generator" has been compiled.
The following is false, see the comments for more info:
Use add_dependencies to add a dependency from "mainproject.exe" to "generate_sources". Now this I have never tested, so take with a grain of salt: With CMake more recent than version 3.12, according to the entry on file, you should then be able to change your file command to:
file(GLOB GeneratedSources CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/src/*.cpp)
Which I interpret as this will re-glob the files during build if the directory changes.

Custom command / target run only for default build not install

I want to build my documentation (doxygen) alongside my project with CMake by default. I let CMake generate Makefiles. I know of these approaches so far:
1)
add_custom_target(doc ALL
COMMAND ${DOXYGEN_COMMAND})
2)
add_custom_command(
TARGET my-executable
POST_BUILD
COMMAND ${DOXYGEN_COMMAND})
The issue I have with the first approach is that the target is build both during build and install (i.e. when running make and when running make install). This is a no-go.
The issue with the second approach is that it is not actually correct: the documentation doesn't have to be built after the executable (in fact, it can be done in parallel even). Moreover I cannot build only the executable now.
Is there a way to create this custom command / target such that it is run only during make (building) and not during make install (installing) but independently from other targets such as executables?
Basically I'd need a "default target". Also I really want to avoid having to execute CMake recursively or make directly.
Just create a file, which existence means that documentation file have been built:
set(documentation_file ${CMAKE__BINARY_DIR}/docs_ready)
# Documentation target
add_custom_target(docs ALL DEPENDS ${documentation_file})
# Documentation command
add_custom_command(OUTPUT ${documentation_file}
COMMAND ${DOXYGEN_COMMAND}
# And mark that documentation is created
COMMAND ${CMAKE_COMMAND} -E touch ${documentation_file}
)
The solution given by #Tsyvarev works perfectly except for one issue:
Running make docs manually doesn't cause a re-build of the documentation because the "output file" ${documentation_file} is always considered up to date (there are no dependencies specified that could be newer).
Three workarounds I found:
Run make -B docs. The -B flags causes GNU Make to consider all targets out of date, and thus causes the documentation to be build.
Add a "manual docs" target which depends on first a docs-clean target which removes ${documentation_file} and then on docs itself (to build the documentation and the file), and run make docs-manual:
add_custom_target(docs-clean
COMMAND ${CMAKE_COMMAND} -E remove ${documentation_file})
add_custom_target(docs-manual)
add_dependencies(docs-manual docs-clean docs)
Note that I fear that this is just a dirty hack: AFAIK the order in which the dependencies (docs-clean and docs) are build isn't specified, and as they don't have a dependency between them, they could even be built in parallel.
Using add_custom_command with a TARGET docs-manual and PRE_BUILD (which runs the command before building dependencies) instead of the docs-clean target would've been perfect, but this only works for Visual Studio 7 or later.
Add a custom target that depends on docs but removes the generated ${documentation_file}:
add_custom_target(docs-manual
COMMAND ${CMAKE_COMMAND} -E remove ${documentation_file})
add_dependencies(docs-manual docs)
This works except for when running it the first time after a make docs, because then the generated file will still be there when docs is built.
edit: Use add_dependencies instead of DEPENDS of add_custom_target because the later is only intended for files, not for dependencies on targets.

Launch host and target crosscompiling builds inside CMake

Is there a way to configure CMake such that a single make command will launch both host and target builds? I have a project that is meant to be run on a target platform but requires some generated data from a generator that needs to run on the host platform (PC). From CMake's documentation and looking around, I need a 2 pass build - first host to create the generator then the target crosscompiling build. My question is specifically how to launch the 2-pass build with a single make command through CMake configurations (not using an external bash or python script).
Things I know
CMake doesn't allow changing toolchain within a single build
Almost solutions like: How to instruct CMake to use the build architecture compiler? Which is fine except I need to skip the 2nd step of using an external script
How to separate what's run during crosscompiling or not cmake - compile natively and crosscompile the same code
It is supposedly possible to launch multiple CMake builds using CMake How to make CMake targeting multiple plattforms in a single build
Turning my comment into an answer
Let's say you have an buildTool sub-directory for the host build tools:
buildTools\CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(BuildTools)
add_executable(genfoo genfoo.cpp)
Then you could have a main:
CMakeLists.txt
if (CMAKE_CROSSCOMPILING)
set(_genfoo "bin/genfoo${CMAKE_EXECUTABLE_SUFFIX}")
add_custom_command(
OUTPUT ${_genfoo}
COMMAND ${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE:STRING="Release"
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE:PATH="${CMAKE_BINARY_DIR}/bin"
-B"bin"
-H"${CMAKE_SOURCE_DIR}/buildTools"
COMMAND ${CMAKE_COMMAND} --build bin --config Release
)
else()
set(_genfoo genfoo)
add_subdirectory(buildTools)
endif()
add_custom_command(
OUTPUT foo.h
COMMAND ${_genfoo}
DEPENDS ${_genfoo}
)
add_executable(bar bar.cpp foo.h)
target_include_directories(bar PRIVATE ${CMAKE_BINARY_DIR})
References
How to instruct CMake to use the build architecture compiler?