add_custom_command depending on another add_custom_command - cmake

We have two add_custom_command clauses, where one depends on the other:
The first command compiles an .osl source file into an .oso object file using the oslc compiler:
set (oslc ${PROJECT_SOURCE_DIR}/sandbox/bin/oslc)
add_custom_command (
OUTPUT "${oso_dir}/${oso_filename}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${oso_dir}"
COMMAND "${oslc}" -I"${osl_include_path}" -o "${oso_dir}/${oso_filename}" "${osl_src_abs}"
MAIN_DEPENDENCY ${osl_src_abs}
DEPENDS ${${headers}} ${osl_src_abs} "${oslc}"
)
Notice the dependency on ${oslc}: we explicitly depend on ${oslc} because we need to make sure it exists before we can execute this command.
The second command "builds" (really, deploys) the oslc compiler by copying it from somewhere else:
add_custom_command (
OUTPUT "${PROJECT_SOURCE_DIR}/sandbox/bin/oslc"
COMMAND ${CMAKE_COMMAND} -E copy ${OSL_COMPILER} ${PROJECT_SOURCE_DIR}/sandbox/bin/
)
While this setup works, it has the side effect that both commands are always executed (the second command followed by the first command) even when the .osl input file hasn't been modified.
It seems that this behavior is specific to Windows. It appears to work fine on Linux.
If the dependency to ${oslc} is removed from the first command, the second command is no longer executed at all, even when the oslc compiler is missing; but on the other hand, .osl files are now only recompiled when they have changed since the last build, as desired (as long as oslc is present).
Is there anything wrong with this setup? If not, what is the right way to combine both features: compiling .osl files only when they have changed since the last build, and "building" the oslc compiler (required by the first step) when it doesn't yet exist?
The actual CMake script is available on GitHub:
Entire CMakeLists.txt file
First add_custom_command clause
Second add_custom_command clause

A simple solution, at least for Windows, is to change the second command to
add_custom_command (
TARGET appleseed.shaders
PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${OSL_COMPILER} ${PROJECT_SOURCE_DIR}/sandbox/bin/
)
(notice the PRE_BUILD keyword)
and to remove the explicit dependency to ${oslc} from the first command.

Related

Why CMake add_custom_command with DEPFILE reruns every time?

I'm trying to write my cmake script as follows:
set(OUTPUT_FILE "${CMAKE_BINARY_DIR}/static_init/generated/${target}/static_init.cpp")
set(DEP_FILE "${CMAKE_BINARY_DIR}/static_init/input/${target}.d")
write_file(${DEP_FILE} "${OUTPUT_FILE}: ")
add_custom_command(
OUTPUT ${OUTPUT_FILE}
COMMAND ${Python3_EXECUTABLE} myscript.py
DEPFILE ${DEP_FILE}
VERBATIM)
I expect, that I will populate .d file during my script first launch and later custom command will be rerun only when one of files listed after colon will change.
Instead command is running during every compilation, even with empty dependencies list. Printing my own sources during cmake run also leads me to constant command rerunning. What am I doing (or understanding) wrong?
CMake 3.18.5
Ninja
Clang
Ninja removes depfiles by default after reading them. This would cause the behavior you are seeing.
Problem was that DEPFILE option and target name inside depfile must be relative to build dir, not absolute paths.
ninja -d explain helped me to find it.

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 call add_subdirectory within custom command

I'm working with a code generator that produces C++ and a CMakeLists.txt file, unfortunately I cannot use this in my main CMakeLists.txt file for testing purposes.
For example you have the following CMakeLists.txt file:
project(SomeProject CXX C)
add_custom_command(OUTPUT ${SRCS}
COMMAND ${CODEGEN_CLI_PATH} -i "${INPUT}" -o "${OUT}"
COMMENT "Generating sources"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
VERBATIM
)
add_custom_target(CODEGEN
DEPENDS
${SRCS}
)
# Needs to be executed after the custom command
add_subdirectory(${GENERATED_CMAKE_LISTS_LOCATION})
Is it possible to use functions such as add_subdirectory only after you execute custom commands for a particular target, such as CODEGEN?
I've already tried to execute it by adding an extra line to the existing custom command:
COMMAND ${CMAKE_COMMAND} -D DIR=${GENERATED_CMAKE_LISTS_LOCATION} -P add_subdirectories.cmake
Unfortuantly this doesn't work because it isn't allowed to execute functions like add_subdirectory in script mode.
Neither I can manage to call custom made functions (that are executing add_subdirectory) from add_custom_command that are located in the same file.
Nope, it is not possible. The add_subdirectory command is run during configuration step, while CODEGEN is a target that runs during build.
You seem to be doing something wrong, so the only advice I can give you is to use execute_process command to run commands you need. The execute_process command is executed during configuration stage, so it will be able to generate files you need before add_subdirectory.
But again, please describe your problem, why do you want CMake to do that.
I have a huge fixed unsigned char array that I compiled into a static library. The way I work around it is by:
if(NOT EXISTS ${PATH_TO_FOLDER}/smeagol.a)
add_subdirectory(smeagol)
endif()
I'm still looking for a nicer kung-fu way to do it using cmake. I feel that its out there, and I will update this answer once i find it.

Why add_custom_command does not work

I am trying to copy one file ${PROJECT_SOURCE_DIR}/abc.h to another location {PROJECT_SOURCE_DIR}/src with the following command:
add_custom_command(
TARGET MyTarget
POST_BUILD
COMMAND -E copy ${PROJECT_SOURCE_DIR}/abc.h
$<"${PROJECT_SOURCE_DIR}/src":MyTarget>)
However, no matter how I try, it seems that the created VC Studio project will not perform the file copy. Any ideas? Thanks.
There are a couple of issues.
First, you want to execute cmake -E copy ... inside the custom command. To do this, you can provide the path to the CMake executable via the variable CMAKE_COMMAND.
Next, you don't need generator expressions in this case. You can just copy from "${PROJECT_SOURCE_DIR}/abc.h" to "${PROJECT_SOURCE_DIR}/src"
So, your final command should be more like:
add_custom_command(
TARGET MyTarget
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_SOURCE_DIR}/abc.h"
"${PROJECT_SOURCE_DIR}/src")
As an aside, if the copied file is forming part of your build, you might be better to use cmake -E copy_if_different ... rather than just copy since this won't update the copied file's timestamp needlessly. (If the file is seen as "updated" all sources that #include it will be recompiled when a rebuild happens).

How do I add a dependency on a script to a target in CMake?

After my program is linked I need to perform some post-processing on it. I added a add_custom_command(TARGET ... and that worked fine. However, this extra custom command runs a script (that is not generated; it's checked into the codebase), and I want the target to be considered out of date if that script changes so it will be rebuilt properly.
The add_dependencies rule seems to only work between top-level elements, which this is not (it's just a script), and there's no DEPENDS element in this form of the add_custom_command that I can use.
How do I do this?
It's unfortunately a bit convoluted, but you can use add_custom_target to invoke CMake in script-processing mode via -P.
You need to use add_custom_target here since it will always execute, even if everything's up to date.
Having made this decision, we need to have the custom target execute commands which will check for a new version of your post-processing script file (let's call this "my_script" and assume it's in your root dir), and if it's changed cause your dependent target to go out of date.
This would comprise:
Compare a previous copy of "my_script" to the current "my_script" in the source tree. If the current "my_script" is different, or if the copy doesn't exist (i.e. this is the first run of CMake) then...
Copy "my_script" from the source tree to the build tree, and...
Touch a source file of the dependent target so that it goes out of date.
All of the commands required inside the CMake script can be achieved using execute_process to invoke cmake -E.
So the CMake script (called e.g. "copy_script.cmake") would be something like:
execute_process(COMMAND ${CMAKE_COMMAND} -E compare_files
${OriginalScript} ${CopiedScript} RESULT_VARIABLE Result)
if(Result)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy
${OriginalScript} ${CopiedScript})
execute_process(COMMAND ${CMAKE_COMMAND} -E touch_nocreate ${FileToTouch})
endif()
The CMake script needs to have required variables passed in via the -D args before calling -P, so the calling CMakeLists.txt would have something like:
set(FileToTouch ${CMAKE_SOURCE_DIR}/src/main.cpp)
add_custom_target(CopyScript ALL ${CMAKE_COMMAND}
-DOriginalScript=${CMAKE_SOURCE_DIR}/my_script
-DCopiedScript=${CMAKE_BINARY_DIR}/my_script
-DFileToTouch=${FileToTouch}
-P ${CMAKE_SOURCE_DIR}/copy_script.cmake)
add_executable(MyExe ${FileToTouch})
This will cause a full rebuild of the executable, since it thinks a source file has been modified. If you only require to force relinking there may be a better way to achieve this.