[cmake-developers] [CMake 0013592]: Inefficient Ninja DAG with add_custom_command

Mantis Bug Tracker mantis at public.kitware.com
Tue Oct 16 10:00:22 EDT 2012


The following issue has been SUBMITTED. 
====================================================================== 
http://public.kitware.com/Bug/view.php?id=13592 
====================================================================== 
Reported By:                Frank Miller
Assigned To:                
====================================================================== 
Project:                    CMake
Issue ID:                   13592
Category:                   CMake
Reproducibility:            always
Severity:                   minor
Priority:                   normal
Status:                     new
====================================================================== 
Date Submitted:             2012-10-16 10:00 EDT
Last Modified:              2012-10-16 10:00 EDT
====================================================================== 
Summary:                    Inefficient Ninja DAG with add_custom_command
Description: 
The ninja generator is not handling dependencies of custom commands
efficiently. As far as I can tell, it is producing correct builds but
with an only overly conservative DAG.

Here is a toy project:

    cmake_minimum_required( VERSION 2.8.0 )
    project( ndep )

    file( WRITE ${CMAKE_BINARY_DIR}/main.cpp "
    #include <iostream>
    #include \"foo.h\"
    int bar();
    int main()
    {
        std::cout << foo() << bar() << std::endl;
    }
    ")

    file( WRITE ${CMAKE_BINARY_DIR}/foo.in "
    int foo() { return VALUE; }
    ")

    file( WRITE ${CMAKE_BINARY_DIR}/bar.in "
    int bar() { return VALUE; }
    ")

    add_custom_command(
      OUTPUT foo.h
      COMMAND cat ${CMAKE_BINARY_DIR}/foo.in | sed 's/VALUE/4/' >
${CMAKE_BINARY_DIR}/foo.h
      DEPENDS ${CMAKE_BINARY_DIR}/foo.in
    )

    add_custom_command(
      OUTPUT bar.cpp
      COMMAND cat ${CMAKE_BINARY_DIR}/bar.in | sed 's/VALUE/2/' >
${CMAKE_BINARY_DIR}/bar.cpp
      DEPENDS ${CMAKE_BINARY_DIR}/bar.in
    )

    add_executable( ndep main.cpp foo.h bar.cpp )

For this case, using git master, the generated object dependencies are
(in Ninja syntax):
  build main.cpp.o: main.cpp | foo.h bar.cpp
  build bar.cpp.o: bar.cpp | foo.h bar.cpp

If foo.h changes (because of foo.in) then bar.cpp.o will be recompiled
when it need not be. Similarly, main.cpp need not be recompiled if
bar.cpp changes. Also, bar.cpp is stated to be both an explicit and an
implicit dependency of bar.cpp.o.

What we want here is:
  build main.cpp.o: main.cpp || foo.h
  build bar.cpp.o: bar.cpp



Additional Information: 
I have studied the Ninja generator code a bit and found the logic
responsible for writing the object build statements in
cmNinjaTargetGenerator::WriteObjectBuildStatement(.) on line 554 in
cmNinjaTargetGenerator.cxx. I see that this logic recently changed.
Previously the generated files would have showed up as order-only
dependencies. This is closer to the desired result but still not
perfect. There must be a better way but I am not familiar enough with
cmake internals to know what that is.

====================================================================== 

Issue History 
Date Modified    Username       Field                    Change               
====================================================================== 
2012-10-16 10:00 Frank Miller   New Issue                                    
======================================================================




More information about the cmake-developers mailing list