Custom command does not get executed with --target option in cmake - cmake

Followup question to this question: cmake project build only one specific executable (and its dependencies)
I have a custom target written so it will run every time i compile something in my project. Now that I call an explicit target as asked in the question above, this custom command does not get executed anymore.
Code:
add_custom_target(
custom_command
ALL
DEPENDS hash.h
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "[INFO] CMake generating special *.h file from custom command magic."
)
I already tried removing the ALL directive but it did not change anything.
Forgot to add: I am using cmake/3.13.4 compiled from source.

Sorry for the later answer but work was crazy. So after i read the comments by #Th.Thielemann and #squareskittles I reread the cmake documentation and found my solution. The following code was written under cmake/3.0.0 quite a while ago:
add_custom_command(
OUTPUT some_header.h
COMMAND cat ${BISON_HEADER} other_header.h | awk -f some_wak_file.awk > some_header.h
DEPENDS ${BISON_HEADER}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
add_custom_target(
custom_command
ALL
DEPENDS some_header.h
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "[INFO] CMake generating special *.h file from custom command magic."
)
After reading up again on the documentation for cmake/3.13 it became quite obvious that it could be written in an easier form:
add_custom_target(
timex_utilities_hash
ALL
COMMAND cat ${BISON_HEADER} other_header.h | awk -f some_wak_file.awk > some_header.h
DEPENDS ${BISON_HEADER}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
Thank you again #Th. Thielemann and #squareskittles for the patients and the inut to check again!

Related

What cmake command will copy a directory of files to a directory in a post build step

I have a set of resource files that have nothing to do with the build steps of GCC or some other compiler's output. I need them copied from a folder in my project to the cmake build output folder. The goal is for the executable, when run from the build output folder, can see the resources.
How do people typically copy and install resources in cmake builds? Additionally, I want them copied regardless of changes in the build and I want it executed every time I run some cmake command, like build. See below for what I tried to solve this issue.
For example:
I have a bunch of shader files that I want copied. All shaders/* files should be copied into a directory in the build output called "shaders", because that's where the executable for the program lives.
file(GLOB out shaders/*)
foreach (o ${out})
message("${o} was copied to shaders")
file(COPY ${o} DESTINATION shaders)
endforeach ()
This only works sometimes, like when I reload the CMake project, e.g.:
/opt/clion-2021.2.3/bin/cmake/linux/bin/cmake \
-DCMAKE_BUILD_TYPE=Debug -DCMAKE_DEPENDS_USE_COMPILER=FALSE \
-G "CodeBlocks - Unix Makefiles" \
/home/hack/glad
Also, it doesn't execute "POST_BUILD", so the lastest version of the shaders/a.vert file doesn't get copied to the shaders/ directory in the output.
I tried using this, too, but it gave me some headaches:
add_custom_command(TARGET my-executable POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy shaders/* shaders)
I think there's something incorrect with that above, because it wasn't run every POST_BUILD if the build's code didn't change. I don't care if the build's code doesn't change because the files in shaders/* could have changed and should be copied regardless of cmake determining if there was a change in my-executable.
This gist on github was very helpful, here but the gist that applies to my question is included below.
add_custom_target(bar
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/shaders
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/shaders ${CMAKE_BINARY_DIR}/shaders
COMMENT "copying ${CMAKE_SOURCE_DIR}/shaders to ${CMAKE_BINARY_DIR}/shaders"
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
The above code creates a bar cmake target that can be run separately with Make bar; then, if you add another target that requires those resources (the shaders above are resources for this other executable) then you can tie the dependency together using add_dependencies like this:
add_executable(a
main.c
opengl.c)
add_dependencies(a bar)
Now, every time the a target is run, the bar target is run as well, which has the effect of creating the directory and copying the files.
This was good enough for me, but to finish up, you can use this to create the files in a post build step after the other dependency is finished running:
add_custom_command(TARGET bar
# Run after all other rules within the target have been executed
POST_BUILD
COMMAND echo "executing a POST_BUILD command"
COMMENT "This command will be executed after building bar"
VERBATIM
)
Note that ${CMAKE_COMMAND} in the above examples of add_custom_command is a variable that points to the cmake executable, and you can run cmake -E to see the very helpful list of commands that come with cmake.
YIKES the post build step is only running after bar's target is built, not a's target. Hopefully, somebody can help me answer this better. I would still like to know how to copy files after a target is built, unless that's completely unnecessary and nobody should ever want to do that.

CMake add_custom_command() POST_BUILD generator expression expansion not working

I want to run a POST_BUILD action after the build (but only in the Debug configuration).
After reading add_custom_command docs and a possible solution I understood that I can "wrap" my COMMAND into $<CONFIG:Debug> generator expression (to be sure it's "empty" in Release mode).
I tried the following:
cmake_minimum_required(VERSION 3.18)
project(post-build CXX)
file(WRITE main.cxx "int main() {}")
add_executable(foo main.cxx)
add_custom_command(
TARGET foo POST_BUILD
COMMAND $<$<CONFIG:Debug>:${CMAKE_COMMAND} -E echo "hi there from debug build">
)
But this gives me the CMake configure-time warnings and a hard failure during a build-time (using Ninja generator):
(...) && "$<1:C:\Program Files\CMake\bin\cmake.exe" -E echo "hi there from debug build" >""
[build] The system cannot find the path specified.
[build] ninja: build stopped: subcommand failed.
[build] Build finished with exit code 1
I tried many possible quotes combinations (including escaped quotes):
COMMAND $<$<CONFIG:Debug>:"${CMAKE_COMMAND} -E echo \"hi there from debug build\"">
and
COMMAND "$<$<CONFIG:Debug>:${CMAKE_COMMAND} -E echo \"hi there from debug build\">"
etc.
But even though it removed the configure-time warning, it still yields a hard error during the build-time.
Question: What would be the correct way to achieve what I want? Is it possible like this or there is a CMake limitation here?
(Note: if possible I'd like to keep the whole command be executed in one place. I am also aware of other workaround possible)
Following the answer of Ben Boeckel here:
Spaces generally aren’t well-formed inside of genexes. You’ll need to replace the spaces with ; to make it parse properly (which is why you’re seeing half-expanded remnants in the build command).
And some discussion in the CMake mailing list (here), what finally worked for me was:
add_custom_command(
TARGET foo POST_BUILD
COMMAND "$<$<CONFIG:Debug>:${CMAKE_COMMAND};-E;echo;\"hi there from debug build\">"
COMMAND_EXPAND_LISTS
)
(Notice the quotes aroung the whole genex, separation with semicolons, backquoting the string, and COMMAND_EXPAND_LISTS to get rid of semicolons in the output -- all-in-all definitely not the most pleasing thing to read)
Edit:
This also works:
set(HELLO_FROM_DEBUG ${CMAKE_COMMAND} -E echo "hi there")
add_custom_command(
TARGET foo POST_BUILD
COMMAND "$<$<CONFIG:Debug>:${HELLO_FROM_DEBUG}>"
COMMAND_EXPAND_LISTS
)

cmake and portable nul / /dev/null device

In my Cmake script I need to redirect the standard output to the NUL / /dev/null device. I searched the CMake documentation for a portable solution but didn't find something.
I could do something like
if (WIN32)
set(NULDEV NUL)
else()
set(NULDEV /dev/null)
endif()
and use in the code ${NULDEV}, but I'd prefer a portable solution coming with CMake.
Edit usage form:
add_custom_target(docs
COMMENT "Generating documentation."
COMMAND ${CMAKE_COMMAND} -E chdir ${PROJECT_BINARY_DIR} "${THE_PROGRAM}" arguments > nul
)
Is this possible?
If you are running a shell command using execute_process() and want to quite the output. you can use the OUTPUT_QUIET and/or ERROR_QUIET options.
From the execute_process documentation:
OUTPUT_QUIET, ERROR_QUIET
The standard output or standard error results will be quietly ignored.
Example 1:
execute_process(COMMAND "${THE_PROGRAM}" argument OUTPUT_QUIET)
If you are using add_custom_target(), then it is unfortunately not that straight forward. What you could do is:
Example 2:
Create a wrapper cmake script for executing your program:
# generate_docs.cmake
execute_process(COMMAND "${THE_PROGRAM}" argument OUTPUT_QUIET)
Let CMake execute the wrapper script instead of running the program directly:
add_custom_target(docs
COMMENT "Generating documentation."
COMMAND ${CMAKE_COMMAND} -P generate_docs.cmake
)

CMake add_custom_command ('POST_BUILD') 'DEPENDS' option is ignored

I have a library and a test projects on CMake, and I'm using this directory structure with two (project) CMakeLists.txt:
/
|- CMakeLists.txt
|- include/libName
|- src/...
|
|- test/
|- CMakeLists.txt
|- src/...
The outer project list defines the library, like:
add_library(libName ${SRC} ${INCLUDE})
And adds 'test' as subdirectory:
add_subdirectory(test)
The test project list defines the executable and a test, like:
add_executable(NameTest ${SRC})
target_link_libraries(NameTest libName)
add_test(NAME NameTest COMMAND NameTest)
The problem
I'm trying to build and execute the test program when the library is built. If any test fails, I want the build of the library fail too.
This is what I have (inside the outer lists file):
add_custom_command(
TARGET libName
POST_BUILD
COMMAND CTEST_OUTPUT_ON_FAILURE=1 ctest
DEPENDS NameTest # <- This is driving me crazy!
)
This command ignores completely if the target 'NameTest' is built, if there is a file with that name, or if not. I can't notice any difference if the whole 'DEPENDS' option is removed.
I even modified like:
add_custom_command(
TARGET libName
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Bip! Bip! Bip!"
DEPENDS this_is_not_an_existent_file_nor_target
)
And the command is triggered anyway. I'm not very sure about if this is the option I need, so:
Why is this not working?
How can I achieve my real purpose?
Thank you.
Edit: ctest will execute every test (add_test), but the NameTest executable (yet listed) must be built before calling it! Now would be built after the library, but before the 'POST_BUILD' custom command. It fails, of course.
I want CMake realize NameTest is necessary for running that custom command.
Edit: I find useful the Angew's answer, so I accepted his answer and refined it a little bit:
add_custom_command(
TARGET libName
POST_BUILD
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target NameTest --config $<CONFIG>
COMMAND ${CMAKE_CTEST_COMMAND} -C $<CONFIG> --output-on-failure
)
Thank you!
1. Why is this not working?
Because you're mixing options from two distinct signatures of add_custom_command. DEPENDS comes from the form which is used to generate a file. TARGET and POST_BUILD are from the form which adds pre/post build commands to existing targets.
See the documentation of add_custom_command for more details on the two uses.
2. How can I achieve my real purpose?
I believe the following should do what you want to:
add_custom_command(
TARGET libName
POST_BUILD
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target NameTest --config $<CONFIG>
COMMAND CTEST_OUTPUT_ON_FAILURE=1 ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target test --config $<CONFIG>
)

How to always run command when building regardless of any dependency?

I want to run a cmake command that parses the whole source tree, so I can't list all possible dependencies in cmake's add_custom_command/add_custom_target commands.
Is it possible to tell cmake just to run a command without any conditions? I tried all solutions found on the net (including SO) but they all assume that the command is dependent on few known files being up to date.
I found a solution but it does not work reliably:
cmake_minimum_required(VERSION 2.6)
project(main)
add_custom_command(
OUTPUT file1
COMMAND echo touching file1
COMMAND touch file1
DEPENDS file2)
add_custom_target(dep ALL DEPENDS file1 file2)
# this command re-touches file2 after dep target is "built"
# and thus forces its rebuild
ADD_CUSTOM_COMMAND(TARGET dep
POST_BUILD
COMMAND echo touching file2
COMMAND touch file2
)
and this is output:
queen3#queen3-home:~/testlib$ make
[100%] Generating file1
touching file1
touching file2
[100%] Built target dep
queen3#queen3-home:~/testlib$ make
[100%] Generating file1
touching file1
touching file2
[100%] Built target dep
queen3#queen3-home:~/testlib$ make
touching file2
[100%] Built target dep
queen3#queen3-home:~/testlib$
As you can see, on third run it did not generate file1, even though file2 was touched previously. Sometimes it happens every 2nd run, sometimes every 3rd, sometimes every 4th. Is it a bug? Is there another way to run a command without any dependency in cmake?
Strange but if I add TWO commands to re-touch file2, i.e. just copy-paste the post-build command, it works reliably. Or maybe it will fail every 1000th run, I'm not sure yet ;-)
While I'm not at all pleased with this solution, posting since I stumbled on this page and didn't see it mentioned.
You can add a custom target that references a missing file,
eg:
if(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/__header.h)
message(FATAL_ERROR "File \"${CMAKE_CURRENT_BINARY_DIR}/__header.h\" found, \
this should never be created, remove!")
endif()
add_custom_target(
my_custom_target_that_always_runs ALL
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/__header.h
)
add_custom_command(
OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/__header.h # fake! ensure we run!
${CMAKE_CURRENT_BINARY_DIR}/header.h # real header, we write.
# this command must generate: ${CMAKE_CURRENT_BINARY_DIR}/header.h
COMMAND some_command
)
This will keep running the custom command because __header.h is not found.
See a working example where this is used.
A twist on ideasman42's answer is to create a dummy output with an empty echo statement. The advantage is that you can have several custom commands depend on this dummy output.
Also, the cmake build system will know what the output file of your custom command is so that any dependencies on that output can be properly resolved.
# Custom target will always cause its dependencies to be evaluated and is
# run by default
add_custom_target(dummy_target ALL
DEPENDS
custom_output
)
# custom_output will always be rebuilt because it depends on always_rebuild
add_custom_command(
OUTPUT custom_output
COMMAND command_that_produces_custom_output
DEPENDS
always_rebuild
)
# Dummy output which is never actually produced. Anything that depends on
# this will always be rebuilt.
add_custom_command(
OUTPUT always_rebuild
COMMAND cmake -E echo
)
The cmake -E echo is as close to a no-op as cmake has.
I searched for exactly the same and I finally found a "notSoWorkaround" solution.
ADD_CUSTOM_TARGET(do_always ALL COMMAND yourCommandRegardlessOfAnyDependency)
This adds a target that will be run after ALL. And as custom targets are always considered out of date it will run always.
You may need DEPENDS yourA.out for running after the build
My sources :
cmake documentation
a mailing list answer for this question
So here's my solution. I add a fake library:
add_subdirectory(fake)
add_dependencies(${PROJECT_NAME} fake)
and there I do this:
cmake_minimum_required (VERSION 2.6)
project(fake CXX)
add_library(${PROJECT_NAME} SHARED fake.cpp)
add_custom_command(TARGET fake
POST_BUILD
COMMAND ./mycommand.sh
COMMAND rm ${ROOT_BIN_DIR}/libfake.so
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
So as you can see I just remove .so file after build, which causes fake lib to be rebuilt each time, with POST_BUILD executed, and all this before the main PROJECT_NAME because it is dependent on fake.