[CMake] Output of ADD_CUSTOM_COMMAND generated multiple times
Brad King
brad.king at kitware.com
Tue Oct 7 16:09:10 EDT 2008
Alan W. Irwin wrote:
> On 2008-10-07 10:22+0200 Martin Apel wrote:
>
>> Hi all,
>>
>> I'm experiencing the following problem with ADD_CUSTOM_COMMAND:
>> The commands defined for it are executed multiple times, if multiple
>> targets depend on it and I run a parallel make afterwards.
>> An example makes this easier to understand:
>>
>> PROJECT(Test)
>> cmake_minimum_required(VERSION 2.6)
>>
>> ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_BINARY_DIR}/a
>> COMMAND ${CMAKE_COMMAND} -E touch
>> ${CMAKE_BINARY_DIR}/a)
>>
>> ADD_CUSTOM_TARGET(b
>> COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_BINARY_DIR}/b
>> DEPENDS ${CMAKE_BINARY_DIR}/a)
>> ADD_CUSTOM_TARGET(c
>> COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_BINARY_DIR}/c
>> DEPENDS ${CMAKE_BINARY_DIR}/a)
>>
>> ADD_CUSTOM_TARGET(world)
>> ADD_DEPENDENCIES(world b)
>> ADD_DEPENDENCIES(world c)
>
> You have run into a CMake limitation which I am told is an inevitable
> result
> of their two-tier dependency approach (file dependencies and target
> dependencies). To avoid the issue you have found for parallel builds you
> must use the following constraint on your CMake logic.
>
> If two targets file depend on the same custom_command output file you must
> serialize them so they don't interfere with each other in a parallel build.
>
> So to bring the above example into compliance with that rule you must
>
> ADD_DEPENDENCIES(c b)
This is not correct. You don't have to serialize anything. You just
need all dependencies to be in place:
-------------------------------------------------------------------
ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_BINARY_DIR}/a
COMMAND ${CMAKE_COMMAND} -E touch
${CMAKE_BINARY_DIR}/a)
ADD_CUSTOM_TARGET(generate_a DEPENDS ${CMAKE_BINARY_DIR}/a)
ADD_CUSTOM_TARGET(b
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_BINARY_DIR}/b
DEPENDS ${CMAKE_BINARY_DIR}/a # file-level dependency
)
ADD_DEPENDENCIES(b generate_a) # target-level dependency
ADD_CUSTOM_TARGET(c
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_BINARY_DIR}/c
DEPENDS ${CMAKE_BINARY_DIR}/a # file-level dependency
)
ADD_DEPENDENCIES(c generate_a) # target-level dependency
ADD_CUSTOM_TARGET(world)
ADD_DEPENDENCIES(world b)
ADD_DEPENDENCIES(world c)
-------------------------------------------------------------------
Now targets b and c and build in parallel, but neither will build until
'a' is generated.
The reason the separate target-level dependency is needed is because
targets b and c might not even know that 'a' is a generated file when
they are created in a different directory.
-Brad
More information about the CMake
mailing list