How to Call a Cmake Function from Add_Custom_Target/Command

How to call a CMake function from add_custom_target/command?

I encountered this issue while writing a CMake build system for BVLC/Caffe. What I finally did is I put the function content into a separate CMake script and called it from within add_custom_target by invoking:

add_custom_target(target_name
COMMAND ${CMAKE_COMMAND} -P path_to_script
)

Invoking CMake with -P flag makes it act as a scripting language. You can put any CMake functions inside the script.

CMake: execute a macro/function as the command of add_custom_command

To prevent that function to run, just wrap it into if:

if(NOT EXISTS ${CMAKE_BINARY_DIR}/blah-blah/generated.cpp)
run_your_provided_command(BLAH_BLAH)
endif()

Easy!

Update: To run it when config file has changed just use little more complicated condition:

if(
NOT EXISTS ${CMAKE_BINARY_DIR}/blah-blah/generated.cpp OR
${CMAKE_SOURCE_DIR}/blah-blah.config IS_NEWER_THAN ${CMAKE_BINARY_DIR}/blah-blah/generated.cpp
)
...

and use add_dependencies command to make sure your binary will be rebuild in case of config file modifications:

add_executable(
YourBinary
...
${CMAKE_BINARY_DIR}/blah-blah/generated.cpp
)
add_dependencies(YourBinary ${CMAKE_SOURCE_DIR}/blah-blah.config)

Calling a macro or a function at POST_BUILD step

The command can be a CMake macro or function. You just have to encapsulate it in a CMake file. CMake's add_custom_command() supports running further CMake code as a script, with the -P option. You can pass arguments to the function using the -D option as well. For this example, we will pass two arguments, TARGET_NAME and TARGET_PATH:

# Define the executable target.
add_executable(MyExecutable ${MY_SRCS})

add_custom_command(TARGET MyExecutable
POST_BUILD
COMMAND ${CMAKE_COMMAND}
-DTARGET_NAME=MyExecutable
-DTARGET_PATH=${CMAKE_CURRENT_SOURCE_DIR}
-P ${CMAKE_SOURCE_DIR}/my_script.cmake
COMMENT "Running script..."
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)

The my_script.cmake file can include one or more pre-defined CMake functions, then call those functions, with something like this:

include(my_function.cmake)
# Call the function, passing the arguments we defined in add_custom_command.
my_function(${TARGET_NAME} ${TARGET_PATH})

For completeness, the CMake function my_function could look like this:

# My CMake function.
function(my_function target_name target_path)
message("Target name: ${target_name}")
message("Target directory: ${target_path}")
endfunction()

What is the function of add_custom_target in CMake?

The command add_custom_command cannot be executed without generating any target. That is why we need the custom target to run this command. What's more, it can only execute at the configure time. If we want to run the command after we configure the CMakeLists.txt file, we can create a custom target to achieve that as the following.

add_custom_target(BLAS_LAPACK_wrappers
WORKING_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS
${MATH_SRCS}
COMMENT
"Intermediate BLAS_LAPACK_wrappers target"
VERBATIM
)

add_custom_command(
OUTPUT
${MATH_SRCS}
COMMAND
${CMAKE_COMMAND} -E tar xzf ${CMAKE_CURRENT_SOURCE_DIR}/wrap_BLAS_LAPACK.tar.gz
WORKING_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/wrap_BLAS_LAPACK.tar.gz
COMMENT
"Unpacking C++ wrappers for BLAS/LAPACK"
)

After we configure the CMakeLists.txt file, we use the Cmake --build . --target=BLAS_LAPACK_wrappers the execute it at the build time.

How to parameterize cmake add_custom_command and add_custom_target?

In CMake the most direct way for parameterize some sequence of actions (for later reuse) is creating a macro or a function. Both of them are allowed to perform any operation which can be written in a plain CMakeLists.txt.

Calling existing make command in cmake file

If you know, which file(s) are produced by Makefile in the subdirectory, and want to depend on these files, use add_custom_command:

add_custom_command(OUTPUT <output-file>
COMMAND make run
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/<subdir>
)

This assumes that your CMakeLists.txt have a target, which depends or uses given file.

Otherwise, if you do not care which files are produced by Makefile, use add_custom_target:

add_custom_target(<target_name> COMMAND make run
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/<subdir>
)

In both cases WORKING_DIRECTORY specifies directory which should be current for command executed.

If you want the target (in the second case) to be executed by default, add ALL option before the COMMAND.



Related Topics



Leave a reply



Submit