cmake: make_directory in built time - cmake

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)

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
)

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

add_custom_command after running a test (CMakeLists)

I'm using a CMakeLists.txt file to generate (among others) some tests. Therefore I have something like
ENABLE_TESTING()
ADD_TEST(NAME my_name COMMAND my_command)
I'd like to add somme commands after the test is run. I found ADD_CUSTOM_COMMAND which seems to do exactly what I need but unfortunately it doesn't work.
Here is what I have tried
ADD_CUSTOM_COMMAND(
TARGET my_name
POST_BUILD
COMMAND my_other_command
)
It seems that I'm not using the right TARGET.
Could you help me by telling me what I'm supposed to do?
Many thanks in advance,
My goal was to execute a diff command after the test execution finished. This is very similar to the problem you are facing. I used this cmake script technique. Leaving it as an answer in case it helps someone else.
In the original CMakeLists.txt file I added a test
add_test(NAME testCommand
COMMAND ${CMAKE_COMMAND}
-DCMD1=$<TARGET_FILE:target>
-DTEST_DATA_DIR=${CMAKE_SOURCE_DIR}
-P ${CMAKE_SOURCE_DIR}/runtests.cmake)
Create a file called runtests.cmake in the directory which has the CMakeLists.txt file. This new file will hold the commands to execute the test and run commands after
include(FindUnixCommands)
macro(EXEC_CHECK CMD)
execute_process(COMMAND ${CMD} ${TEST_DATA_DIR}/test_input.txt RESULT_VARIABLE CMD_RESULT)
if(CMD_RESULT)
message(FATAL_ERROR "Error running ${CMD}")
else()
if (BASH)
execute_process(COMMAND ${BASH} -c "diff -b ${TEST_DATA_DIR}/test_input.txt ${TEST_DATA_DIR}/test_output.txt" RESULT_VARIABLE RES)
if(RES)
message(FATAL_ERROR "Diff is not clean")
endif()
else(BASH)
message(FATAL_ERROR "BASH not found : no diff script run")
endif(BASH)
endif()
endmacro()
exec_check(${CMD1})
From the build directory I can now issue make test and it picks up the cmake script properly.

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.

Creating a directory in CMake

In CMake, I want to create a directory if it doesn't already exist. How can I do this?
When do you want to create the directory?
At build system generation
To create a directory when CMake generates the build system,
file(MAKE_DIRECTORY ${directory})
At build time
In the add_custom_command() command (which adds a custom build rule to the generated build system), and the add_custom_target() command (which adds a target with no output so it will always be built), you specify the commands to execute at build time. Create a directory by executing the command ${CMAKE_COMMAND} -E make_directory. For example:
add_custom_target(build-time-make-directory ALL
COMMAND ${CMAKE_COMMAND} -E make_directory ${directory})
At install time
To create a directory at install time,
install(DIRECTORY DESTINATION ${directory})
To create a directory at install time,
install(DIRECTORY DESTINATION ${directory})
These will both run at configure time:
file(MAKE_DIRECTORY ${directory})
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${directory})
To create during the build, use a custom target:
add_custom_target(mytargetname ALL COMMAND ${CMAKE_COMMAND} -E make_directory ${directory})
In addition to Chin Huang's reply, you can also do this at build time with add_custom_command:
add_custom_command(TARGET ${target_name} PRE_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory ${directory})
You can also change the moment, when your directory is created with PRE_BUILD | PRE_LINK | POST_BUILD parameters.