[CMake] FYI - From Ninja-build mailing list - Fwd: Proposal: restat rules

Andreas Mohr andi at lisas.de
Thu Sep 15 09:28:42 EDT 2011


Hi,

On Wed, Sep 14, 2011 at 12:00:05PM -0400, cmake-request at cmake.org wrote:
> Date: Wed, 14 Sep 2011 05:37:20 -0400
> From: Clifford Yapp <cliffyapp at gmail.com>
> 
> Looks like that's working.  Running ninja again, I'm seeing another issue:
> 
> BRL-CAD uses dependency assignment to make sure our build time delta
> calculator is the last target to be built (and hence actually times the
> build).  With ninja, it doesn't seem to be respecting this, but instead
> tries to run the delta target immediately.  Do custom targets respect
> dependency information?

I'm seeing the same thing here, and I think I semi-nailed it.

I've got:

function(scm_sos_pull_db_tree _pull_target _scm_dir)
  if(NOT TARGET scm_sos_pull_db_tree)
    # this crap does not work the way it should...
    #set(scm_spec "${scm_repo_prefix}/${_scm_dir}")
    set(scm_spec "${scm_repo_prefix}")

    #set(stamp_file_tree "${sos_wrapper_stamps_dir}/scm_sos_pull_db_tree_${_pull_target}.stamp")
    set(stamp_file_tree "${sos_wrapper_stamps_dir}/scm_sos_pull_db_tree.stamp")
    set(db_tree_output "${sos_wrapper_db_file_pathname}")
    add_custom_command(OUTPUT "${db_tree_output}"
      COMMAND ${sos_wrapper_cmdline_constant_part} "-project ${scm_spec} -command GetProjectTree"
      COMMAND "${CMAKE_COMMAND}" -E touch "${stamp_file_tree}"
      # Cannot specify the full ${scm_sos_dependencies} list here
      # (we're creating the very database file that it lists).
      # And we should avoid adding ${sos_wrapper_script} as a dependency
      # here, since a simple update of that script most certainly doesn't
      # justify doing the _AWFULLY_ lengthy operation of pulling
      # the entire database anew. All other SCM targets _should_ properly depend on
      # SosWrap.bash, however, since they're much cheaper...
      DEPENDS "${MASTER_SCM_HAS_BEEN_UPDATED}"
      COMMENT "fetching SOS SCM database tree for ${scm_spec}"
      VERBATIM
    )
    add_custom_target(scm_sos_pull_db_tree VERBATIM DEPENDS "${db_tree_output}")
    add_dependencies(scm_sos_pull_db_tree scm_sos_setup)
  endif(NOT TARGET scm_sos_pull_db_tree)
  # add a dependency to make sure that before pulling a file/project we fetch its project tree
  add_dependencies(${_pull_target} scm_sos_pull_db_tree)
endfunction(scm_sos_pull_db_tree _pull_target _scm_dir)


So you can see that I'm clearly adding a dependency of target scm_sos_pull_db_tree on the
target scm_sos_setup (which is the one to make sure that the SosWrap.bash script
is properly prepared before continuing).


However, what I'm ending up with is:



# Phony custom command for CMakeFiles/scm_sos_pull_db_tree
build CMakeFiles/scm_sos_pull_db_tree: phony _SCM/sos/database/servers/SERVER/DATABASE.sos
# Utility command for scm_sos_pull_db_tree
build scm_sos_pull_db_tree: phony CMakeFiles/scm_sos_pull_db_tree _SCM/sos/database/servers/SERVER/DATABASE.sos scm_sos_setup
# Phony custom command for CMakeFiles/scm_sos_setup
build CMakeFiles/scm_sos_setup: phony _SCM/sos/stamps/sos_setup.stamp
# Custom command for _SCM/sos/stamps/sos_setup.stamp
build _SCM/sos/stamps/sos_setup.stamp: CUSTOM_COMMAND
  COMMAND = cd [[CMAKE_BINARY_DIR]] && /usr/local/bin/cmake -E make_directory [[CMAKE_BINARY_DIR]]/_SCM/sos/stamps && /usr/local/bin/cmake -E touch [[CMAKE_BINARY_DIR]]/_SCM/sos/stamps/sos_setup.stamp
  DESC = Generating _SCM/sos/stamps/sos_setup.stamp
# Utility command for scm_sos_setup
build scm_sos_setup: phony CMakeFiles/scm_sos_setup _SCM/sos/stamps/sos_setup.stamp copy_prep_file__[[CMAKE_BINARY_DIR]]_SosWrap.bash


IOW, from what I'm gathering here, it seems as if   scm_sos_pull_db_tree   lists   its _internal_
target/rule/whatever CMakeFiles/scm_sos_pull_db_tree with same-hierarchy priority as scm_sos_setup.
And that internal target/rule/whatever then gets executed in advance, despite scm_sos_setup not having been executed (prepared) yet.

And this is most likely because add_custom_command() in Ninja generator
actually gets realised as an inner target of its corresponding CMake add_custom_target(),
and we then have a logical disconnect since it's the _outer_, CMake-_public_ target
which gets configured a constraint ("scm_sos_setup needs to run first").


IOW, it's a MISTAKE to implement (emulate) add_custom_command() via inner targets in Ninja build config,
since those inner targets don't inherit those dependency constraints ("ordering")
which have been explicitly imposed on their outer targets.

So:
- either keep custom commands implemented via inner targets - and then make sure
  that those inner (internal!) targets do have _all_ dependencies of the outer,
  CMake-public target specified
- or don't implement custom commands via internal, logically disconnected targets  [better?]


Or am I missing something?
(I believe my CMake construct is correct - but who knows...)

OK, I should perhaps add a file dependency (DEPENDS) within add_custom_command() on the
SosWrap.bash script (but that was done _very_ deliberately - see comment in that function() above,
and the purpose of that DEPENDS is usually solely to trigger a _rebuild_
in case the file dependency changed, and that does work properly with Unix Makefiles
- actual execution _ordering_ is supposed to be done by specification of corresponding
target dependencies, and this is what fails with Ninja generator).


Ninja generator - blazingly fast execution due to guillotineing some 72.13% of all dependencies? ;->
(whoa, that perhaps was almost as severe as an ad-hominem ;)



Thanks a lot again for your very valuable work!

Andreas Mohr


More information about the CMake mailing list