[cmake-developers] [CMake 0015456]: Ninja manifests generated for CMake configuration steps should probably not have RERUN_CMAKE steps

Mantis Bug Tracker mantis at public.kitware.com
Wed Mar 18 12:38:15 EDT 2015


The following issue has been SUBMITTED. 
====================================================================== 
http://www.cmake.org/Bug/view.php?id=15456 
====================================================================== 
Reported By:                Daniel Dunbar
Assigned To:                
====================================================================== 
Project:                    CMake
Issue ID:                   15456
Category:                   (No Category)
Reproducibility:            have not tried
Severity:                   minor
Priority:                   normal
Status:                     new
====================================================================== 
Date Submitted:             2015-03-18 12:38 EDT
Last Modified:              2015-03-18 12:38 EDT
====================================================================== 
Summary:                    Ninja manifests generated for CMake configuration
steps should probably not have RERUN_CMAKE steps
Description: 
The Ninja manifests that CMake generates as part of its initial configuration
(e.g., checking if the C compiler works) include the commands to rerun the
generator, even though it would never make sense for the generator to
automatically be rerun by Ninja in such a context.

This is wasteful of space/time in the manifest, but it also could be a serious
problem if something ever causes Ninja to want to rerun the generator at that
point. If it did, it could end up rerunning the same configuration checks (but
under CMakeFiles/CMakeTmp), which would then trigger an infinite loop of
configuration checks (in ever deepening
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/...).

--

The reason why I noticed this problem is that I was looking at Ninja's behavior
w.r.t. skipping rerunning of command when it is newer than the inputs. Ninja
will currently skip running a command when the output has the same timestamp as
the newest input. On OS X, this is not particularly safe, as the HFS filesystem
has a 1s resolution on the mod times, and so it is very easy for the input to be
"newer" than (modified after) the output and still not get rebuilt by Ninja. I
was curious if changing Ninja to use a strict newer-than check would work.

The way this relates to the aforementioned issue is that the RERUN_CMAKE command
in the build.ninja files generated for the configuration checks depend on other
.cmake files generated at the same time, and they are very likely to have the
same timestamp on OS X. If Ninja did a more strict check here, it would cause it
to rerun the generator as part of the configuration commands, and trigger an
infinite loop... see steps to reproduce.

It seems like it would be safer and more efficient to avoid generating the
RERUN_CMAKE rules into these build.ninja files in the first place.

Steps to Reproduce: 
There isn't a trivial way to see this problem, but if you build a custom version
of Ninja that uses a stricter newer-than check for comparing outputs to inputs
using the following patch (against 717619a260633ca0e7c9eb2366130fc06ebacfff):
--
diff --git a/src/graph.cc b/src/graph.cc
index 76c4e9a..4b45015 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -148,7 +148,7 @@ bool DependencyScan::RecomputeOutputDirty(Edge* edge,
   }
 
   // Dirty if the output is older than the input.
-  if (most_recent_input && output->mtime() < most_recent_input->mtime()) {
+  if (most_recent_input && output->mtime() <= most_recent_input->mtime()) {
     TimeStamp output_mtime = output->mtime();
 
     // If this is a restat rule, we may have cleaned the output with a restat
@@ -162,7 +162,7 @@ bool DependencyScan::RecomputeOutputDirty(Edge* edge,
       used_restat = true;
     }
 
-    if (output_mtime < most_recent_input->mtime()) {
+    if (output_mtime <= most_recent_input->mtime()) {
       EXPLAIN("%soutput %s older than most recent input %s "
               "(%d vs %d)",
               used_restat ? "restat of " : "", output->path().c_str(),
--

then you can reproduce the problem trivially with an empty CMakeLists.txt:

--

$ ls -la CMakeLists.txt
-rw-r--r--  1 ddunbar  staff  35 Mar 18 09:34 CMakeLists.txt
$ cmake -GNinja .
-- The C compiler identification is AppleClang 7.0.0.7000009
-- The CXX compiler identification is AppleClang 7.0.0.7000009
-- Check for working C compiler using: Ninja
  C-c C-c
$ find CMakeFiles | head -50
CMakeFiles
CMakeFiles/3.2.1
CMakeFiles/3.2.1/CMakeCCompiler.cmake
CMakeFiles/3.2.1/CMakeCXXCompiler.cmake
CMakeFiles/3.2.1/CMakeSystem.cmake
CMakeFiles/3.2.1/CompilerIdC
CMakeFiles/3.2.1/CompilerIdC/CMakeCCompilerId.c
CMakeFiles/3.2.1/CompilerIdC/a.out
CMakeFiles/3.2.1/CompilerIdCXX
CMakeFiles/3.2.1/CompilerIdCXX/CMakeCXXCompilerId.cpp
CMakeFiles/3.2.1/CompilerIdCXX/a.out
CMakeFiles/CMakeOutput.log
CMakeFiles/CMakeTmp
CMakeFiles/CMakeTmp/.ninja_deps
CMakeFiles/CMakeTmp/.ninja_log
CMakeFiles/CMakeTmp/CMakeCache.txt
CMakeFiles/CMakeTmp/CMakeFiles
CMakeFiles/CMakeTmp/CMakeFiles/3.2.1
CMakeFiles/CMakeTmp/CMakeFiles/3.2.1/CMakeCCompiler.cmake
CMakeFiles/CMakeTmp/CMakeFiles/3.2.1/CMakeSystem.cmake
CMakeFiles/CMakeTmp/CMakeFiles/3.2.1/CompilerIdC
CMakeFiles/CMakeTmp/CMakeFiles/3.2.1/CompilerIdC/CMakeCCompilerId.c
CMakeFiles/CMakeTmp/CMakeFiles/3.2.1/CompilerIdC/a.out
CMakeFiles/CMakeTmp/CMakeFiles/CMakeOutput.log
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/.ninja_deps
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/.ninja_log
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeCache.txt
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/3.2.1
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/3.2.1/CMakeCCompiler.cmake
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/3.2.1/CMakeSystem.cmake
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/3.2.1/CompilerIdC
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/3.2.1/CompilerIdC/CMakeCCompilerId.c
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/3.2.1/CompilerIdC/a.out
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeOutput.log
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/.ninja_deps
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/.ninja_log
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeCache.txt
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/3.2.1
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/3.2.1/CMakeCCompiler.cmake
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/3.2.1/CMakeSystem.cmake
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/3.2.1/CompilerIdC
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/3.2.1/CompilerIdC/CMakeCCompilerId.c
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/3.2.1/CompilerIdC/a.out
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeOutput.log
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp
CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/CMakeFiles/CMakeTmp/.ninja_deps
$ 
--
====================================================================== 

Issue History 
Date Modified    Username       Field                    Change               
====================================================================== 
2015-03-18 12:38 Daniel Dunbar  New Issue                                    
======================================================================



More information about the cmake-developers mailing list