Consider a command which generates file3 and file4 from file1 and file2
In CMake the build rule is added with a call to add_custom_command:
add_custom_command(
OUTPUT file3 file4
DEPENDS file1 file2
COMMAND command)
During a build the command runs if and only if:
Note that the command might run even though the outputs which are dependencies of targets being built are already up to date, because of other outputs which aren't up to date.
For an example, see the copy file example.
In GNU make the above example would be represented by a rule written with the following syntax:
# GNU makefile
file3 file4 : file1 file2
command
This does two things:
add_custom_command is not equivalent to the GNU make rule in the sense that add_custom_command doesn't define any targets. That means the OUTPUTs are not available as targets for make commands. See the stack overflow discussion add_custom_command is not generating a target.
If only some of the declared outputs change then some downstream outputs/targets may avoid needing to to be built. For example consider the following cmake script:
add_custom_target(T ALL DEPENDS o3 o4)
add_custom_command(
OUTPUT o3
DEPENDS o1
COMMAND ${CMAKE_COMMAND} -E copy o1 o3)
add_custom_command(
OUTPUT o4
DEPENDS o2
COMMAND ${CMAKE_COMMAND} -E copy o2 o4)
add_custom_command(
OUTPUT o1 o2
DEPENDS f1 f2
COMMAND ${CMAKE_COMMAND} -E copy_if_different f1 o1
COMMAND ${CMAKE_COMMAND} -E copy_if_different f2 o2)
Note that the timestamps of o1,o2 can be older than the timestamps of the dependencies f1,f2. This happens when f1,f2 are touched, but otherwise unchanged. copy_if_different doesn't perform a copy in that case, so the files o1,o2 aren't touched.
The cmake documentation of add_custom_command for BYPRODUCTS states it is used to:
Specify the files the command is expected to produce but whose modification time may or may not be newer than the dependencies.
It is unclear whether the above cmake script is invalid.
CMP0058 states
Byproducts may not be listed as outputs because their timestamps are allowed to be older than the inputs.
It is unclear whether "may not" is intended to mean "must not", or "may not necessarily".
Note that if no OUTPUT is specified then cmake produces an error: "add_custom_command Wrong syntax. A TARGET or OUTPUT must be specified". This could be fixed with a witness file - as discussed in CMP0058.
Testing with the ninja generator doesn't show any problems, the output files can be deleted, input files can be touched or updated, and copies are performed when and only when they are required.
For example, consider that everything has been built, then f1 is changed, then another build is performed. f1 will be copied to o1, and o1 will be copied to o3. However o2 won't be touched (because copy_if_different is used and f2 is unchanged). Therefore the copy from o2 to o4 won't run.