What is the exact order guarantee that CMake add_dependencies gives?
11:59 08 Nov 2025

We are using CMake and ninja to build our project. We wanted to regenerate a cpp file at every build, containing the build timestamp, so that our executable can log it. We came up with this:

####################
# Embed build time #
####################

find_package(Python3 REQUIRED COMPONENTS Interpreter)

set(TIMESTAMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated_timestamp)
set(TIMESTAMP_CPP ${TIMESTAMP_DIR}/timestamp.cpp)
set(TIMESTAMP_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/generate_timestamp.py)

file(MAKE_DIRECTORY ${TIMESTAMP_DIR})

add_custom_target(generate_timestamp_files
  COMMAND ${Python3_EXECUTABLE} ${TIMESTAMP_SCRIPT} ${TIMESTAMP_CPP}
  DEPENDS ${TIMESTAMP_SCRIPT}
  COMMENT "Generating timestamp source and header"
)

set_source_files_properties(
    ${TIMESTAMP_CPP}
    PROPERTIES
    GENERATED TRUE
)

add_library(timestamp_lib
    ${TIMESTAMP_CPP}
)

add_dependencies(timestamp_lib generate_timestamp_files) # HERE

target_include_directories(timestamp_lib
  PUBLIC
  include
)

target_link_libraries(main_target
    timestamp_lib
)

Notice the call to add_dependencies. Now this configuration works, the cpp file is regenerated at every build, but the library only gets recompiled every two builds. Why? My understanding is that add_dependencies should force ninja to wait to check for the library until the file has been regenerated, at which point the timestamp should be newer than the library. Apparently the are working in parallel? The CMake manual mentions:

add_dependencies( ...) [...] Changed in version 3.9: The Ninja Generators use weaker ordering than other generators in order to improve available concurrency. They only guarantee that the dependencies' custom commands are finished before sources in start compiling; this ensures generated sources are available.

But isn't this sufficient? Thanks!

c++ cmake build dependencies ninja