MantisBT - CMake
View Issue Details
0015456CMake(No Category)public2015-03-18 12:382016-06-10 14:31
Daniel Dunbar 
Kitware Robot 
normalminorhave not tried
closedmoved 
CMake 3.2.1 
 
0015456: Ninja manifests for try_compile projects should not have RERUN_CMAKE steps
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.
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
$
--
No tags attached.
Issue History
2015-03-18 12:38Daniel DunbarNew Issue
2015-03-18 13:18Brad KingSummaryNinja manifests generated for CMake configuration steps should probably not have RERUN_CMAKE steps => Ninja manifests for try_compile projects should not have RERUN_CMAKE steps
2015-03-18 13:29Brad KingNote Added: 0038238
2015-03-18 13:35Brad KingNote Added: 0038239
2016-06-10 14:29Kitware RobotNote Added: 0042735
2016-06-10 14:29Kitware RobotStatusnew => resolved
2016-06-10 14:29Kitware RobotResolutionopen => moved
2016-06-10 14:29Kitware RobotAssigned To => Kitware Robot
2016-06-10 14:31Kitware RobotStatusresolved => closed

Notes
(0038238)
Brad King   
2015-03-18 13:29   
Thanks. I revised the description a bit.
(0038239)
Brad King   
2015-03-18 13:35   
When try_compile generates a test project it sets CMAKE_SUPPRESS_REGENERATION:

 http://www.cmake.org/gitweb?p=cmake.git;a=blob;f=Source/cmCoreTryCompile.cxx;hb=v3.2.1#l371 [^]

The Ninja generator should be taught to honor this by not adding the RERUN_CMAKE rule.
(0042735)
Kitware Robot   
2016-06-10 14:29   
Resolving issue as `moved`.

This issue tracker is no longer used. Further discussion of this issue may take place in the current CMake Issues page linked in the banner at the top of this page.