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

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>
)

Related

Split CMake generator expression into function arguments

I have the following CMake segment to copy some DLLs I require into the output folder of my executable:
file(GLOB Debug_DLLS "${SDK_DIR}/Libs/*.dll")
file(GLOB Release_DLLS "${SDK_DIR}/Libsr/*.dll")
add_custom_command(TARGET myApp POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<$<CONFIG:Debug>:${Debug_DLLS}>
$<$<NOT:$<CONFIG:Debug>>:${Release_DLLS}>
$<TARGET_FILE_DIR:myApp>
)
copy_if_different is supposed to support multiple arguments.
I am 100% sure that SDK_DIR is a valid folder and also that the Release_DLLS and Debug_DLLS variable is valid. The code works if I just put in a simple filepath into Release_DLLs.
But when building I simply get the error: "The system cannot find the provided path" in my native system language. Why isn't this working with multiple files?
I needed to quote the generator expressions and add COMMAND_EXPAND_LISTS to the command.
The following code works and is probably the most flexible solution to copy different DLLs to the output directory based on the build type:
file(GLOB Debug_DLLS "${SDK_DIR}/Libs/*.dll")
file(GLOB Release_DLLS "${SDK_DIR}/Libsr/*.dll")
add_custom_command(TARGET myApp POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"$<$<CONFIG:Debug>:${Debug_DLLS}>"
"$<$<NOT:$<CONFIG:Debug>>:${Release_DLLS}>"
$<TARGET_FILE_DIR:myApp>
COMMAND_EXPAND_LISTS
)

Empty RUNTIME_OUTPUT_DIRECTORY

Working on a project using CMake. This project contains an executable and a python script. These two files should be compiled/copied in the same directory at build.
I try something like :
add_executable( ${myTarget} ${all_c_sources} )
add_custom_command(
TARGET ${myTarget} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${pythonScriptPath} ${RUNTIME_OUTPUT_DIRECTORY}/
)
The executable is well build in a default location like ${CMAKE_BINARY_DIR}/Debug but the copy of the python script failed :
c:\Program Files (x86)\CMake\bin\cmake.exe" -E copy C:/.../script.py /\r
My goal is to use CMake default behavior as mush as possible.
Is there a simple way to get the default output path ?
Thanks !
Something like this:
add_custom_command(TARGET ${LIBRARY_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:${LIBRARY_NAME}>
$<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/path/to/where/module/should/be
COMMENT "Copying file to Runtime directory: " $<TARGET_FILE:${LIBRARY_NAME}>
)
Adjust it to your needs.
Read about CMake Generator Expressions if you need to know more.

CMake/CPack: add_custom_command TARGET package POST_BUILD

Having the same problem as here described, I want to execute a shell script as a POST_BUILD command of TARGET "package". Target platform is Debian/Ubuntu.
I add following to the end of my CMakeLists:
add_custom_command(
TARGET package
POST_BUILD
COMMAND bash ${PROJECT_BINARY_DIR}/fixup_deb.sh
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
COMMENT "Fix file-permissions of md5sum files in debian package"
)
But this does not work. When I call "make package" the script doesn't change.
At the moment I have a workaround with a custom target:
add_custom_target(
correctDeb
COMMAND bash ${PROJECT_BINARY_DIR}/fixup_deb.sh
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
)
But it would be much more comfortable and more fail-safe for me if this would be automagically done when calling "make package".
By the way, generation of ${PROJECT_BINARY_DIR}/fixup_deb.sh works also well with:
configure_file( "${CMAKE_CURRENT_LIST_DIR}/debian/fixup_deb.sh.in" "${PROJECT_BINARY_DIR}/fixup_deb.sh" #ONLY IMMEDIATE )

How can I write a CMake test that will show build errors?

I currently have this ingenious code that adds my single-source-file tests to my CMake project:
function(runtime_test test_dir test_name)
add_executable(${test_name} EXCLUDE_FROM_ALL ${TEST_ROOT}/${test_dir}/${test_name}.c++ ${TEST_ROOT}/test.h++)
set_target_properties(${test_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY test/${test_dir})
#add_test(remove/${test_dir}/${test_name} ${CMAKE_COMMAND} -E remove test/${test_dir}/${test_name}${CMAKE_EXECUTABLE_SUFFIX})
#add_test(build/${test_dir}/${test_name} ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ${test_name})
#add_test(test/${test_dir}/${test_name} test/${test_dir}/${test_name})
add_test(${test_dir}/${test_name} ${CMAKE_COMMAND} -E remove test/${test_dir}/${test_name}${CMAKE_EXECUTABLE_SUFFIX}
&& ${CMAKE_COMMAND} --verbose --build ${CMAKE_BINARY_DIR} --target ${test_name}
&& test/${test_dir}/${test_name})
set_property(TEST ${test_dir}/${test_name} APPEND PROPERTY DEPENDS build/${test_dir}/${test_name})
endfunction()
The commented lines add 3 "tests" which remove, build and run an executable. I run a single test as follows:
ctest --verbose -R some_test
With the commented 3 lines, I can see the build errors output to my screen. Problem is: this makes the number of tests non-representative. If I use the 3-in-1 solution, the build error output is hidden. Is there any way to solve this?

cmake: make_directory in built time

I have this code that runs during configuration time:
if (NOT EXISTS "${PROJECT_BINARY_DIR}/tmpdir/")
file (MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/tmpdir/")
message ("Generating tmpdir directory")
endif ()
How do I implement the above code but in build time?
How do I implement the above code but in build time?
It depends on when you exactly need this directory. For instance if you need it before executable foo compiled, you can use add_custom_target and add_dependencies:
add_custom_target(
make_temp
"${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/tmpdir"
COMMENT "Create 'tmpdir'"
)
add_executable(foo ...)
add_dependencies(foo make_temp)