Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r78250 - in trunk/tools/build/v2: engine test
From: steven_at_[hidden]
Date: 2012-04-28 21:06:56


Author: steven_watanabe
Date: 2012-04-28 21:06:55 EDT (Sat, 28 Apr 2012)
New Revision: 78250
URL: http://svn.boost.org/trac/boost/changeset/78250

Log:
Stop targets that depend on an include cycle from updating before all the required generated headers are built.
Text files modified:
   trunk/tools/build/v2/engine/make1.c | 94 ++++++++++++++++++++++++++++++++++-----
   trunk/tools/build/v2/engine/rules.h | 1
   trunk/tools/build/v2/test/rescan_header.py | 80 +++++++++++++++++++++++++++++++--
   3 files changed, 158 insertions(+), 17 deletions(-)

Modified: trunk/tools/build/v2/engine/make1.c
==============================================================================
--- trunk/tools/build/v2/engine/make1.c (original)
+++ trunk/tools/build/v2/engine/make1.c 2012-04-28 21:06:55 EDT (Sat, 28 Apr 2012)
@@ -74,7 +74,9 @@
 static LIST * make1list ( LIST *, TARGETS *, int flags );
 static SETTINGS * make1settings( struct module_t * module, LIST * vars );
 static void make1bind ( TARGET * );
-static int make1findcycle( TARGET * t );
+static TARGET * make1findcycle( TARGET * t );
+static void make1breakcycle( TARGET * t, TARGET * cycle_root );
+static TARGET * make1scc ( TARGET * );
 
 /* Ugly static - it is too hard to carry it through the callbacks. */
 
@@ -277,16 +279,24 @@
      * target is built.
      */
     if ( pState->parent )
- switch ( pState->t->progress )
+ {
+ TARGET * dependency = make1scc( t );
+ switch ( dependency->progress )
         {
+ case T_MAKE_ONSTACK:
+ make1breakcycle( pState->parent, dependency ); break;
             case T_MAKE_ACTIVE:
- if ( handling_rescan && make1findcycle( t ) ) break;
+ if ( handling_rescan && make1findcycle( dependency ) )
+ {
+ make1breakcycle( pState->parent, dependency ); break;
+ }
             case T_MAKE_INIT:
             case T_MAKE_RUNNING:
- pState->t->parents = targetentry( pState->t->parents,
+ dependency->parents = targetentry( dependency->parents,
                     pState->parent );
                 ++pState->parent->asynccnt;
         }
+ }
 
     /*
      * If the target has been previously updated with -n in
@@ -646,8 +656,22 @@
                 push_state( &temp_stack, additional_includes, NULL, T_STATE_MAKE1CTAIL );
             }
 
- for ( c = t->parents; c; c = c->next )
- push_state( &temp_stack, c->target, NULL, T_STATE_MAKE1B );
+ if ( t->scc_root )
+ {
+ TARGET * scc_root = make1scc( t );
+ for ( c = t->parents; c; c = c->next )
+ {
+ if ( make1scc( c->target ) == scc_root )
+ push_state( &temp_stack, c->target, NULL, T_STATE_MAKE1B );
+ else
+ scc_root->parents = targetentry( scc_root->parents, c->target );
+ }
+ }
+ else
+ {
+ for ( c = t->parents; c; c = c->next )
+ push_state( &temp_stack, c->target, NULL, T_STATE_MAKE1B );
+ }
 
 #ifdef OPT_SEMAPHORE
             /* If there is a semaphore, it is now free. */
@@ -1182,20 +1206,41 @@
 }
 
 
-static int make1findcycle_impl( TARGET * t )
+static void make1cyclenode( TARGET * t, TARGET * scc_root )
+{
+ /* if we intersect with another cycle we need to merge the two */
+ if ( t->scc_root )
+ {
+ TARGET * other_root = make1scc( t );
+ if ( other_root != scc_root )
+ {
+ other_root->scc_root = scc_root;
+ other_root->parents = targetentry( other_root->parents, scc_root );
+ ++scc_root->asynccnt;
+ }
+ }
+ t->scc_root = scc_root;
+}
+
+
+static TARGET * make1findcycle_impl( TARGET * t, TARGET * scc_root )
 {
     TARGETS * c;
+ TARGET * result;
 
     if ( t->progress == T_MAKE_ONSTACK )
- return 1;
+ return t;
     else if ( t->progress != T_MAKE_ACTIVE )
         return 0;
 
     t->progress = T_MAKE_FINDCYCLE;
 
     for ( c = t->depends; c; c = c->next )
- if ( make1findcycle_impl( c->target ) )
- return 1;
+ if ( ( result = make1findcycle_impl( c->target, scc_root ) ) )
+ {
+ make1cyclenode( c->target, scc_root );
+ return result;
+ }
 
     return 0;
 }
@@ -1213,9 +1258,34 @@
         make1findcycle_cleanup( c->target );
 }
 
-static int make1findcycle( TARGET * t )
+static TARGET * make1findcycle( TARGET * t )
 {
- int result = make1findcycle_impl( t );
+ TARGET * result = make1findcycle_impl( t, t );
     make1findcycle_cleanup( t );
     return result;
 }
+
+static void make1breakcycle( TARGET * t, TARGET * cycle_root )
+{
+ TARGET * scc_root = make1scc( cycle_root );
+ while ( t != cycle_root )
+ {
+ make1cyclenode( t, scc_root );
+ t = t->parents->target;
+ }
+}
+
+static TARGET * make1scc( TARGET * t )
+{
+ TARGET * result = t;
+ TARGET * tmp;
+ while ( result->scc_root )
+ result = result->scc_root;
+ while ( t->scc_root )
+ {
+ tmp = t->scc_root;
+ t->scc_root = result;
+ t = tmp;
+ }
+ return result;
+}

Modified: trunk/tools/build/v2/engine/rules.h
==============================================================================
--- trunk/tools/build/v2/engine/rules.h (original)
+++ trunk/tools/build/v2/engine/rules.h 2012-04-28 21:06:55 EDT (Sat, 28 Apr 2012)
@@ -227,6 +227,7 @@
 
     int asynccnt; /* child deps outstanding */
     TARGETS * parents; /* used by make1() for completion */
+ TARGET * scc_root; /* used by make1 to resolve cyclic includes */
     char * cmds; /* type-punned command list */
 
     const char * failed;

Modified: trunk/tools/build/v2/test/rescan_header.py
==============================================================================
--- trunk/tools/build/v2/test/rescan_header.py (original)
+++ trunk/tools/build/v2/test/rescan_header.py 2012-04-28 21:06:55 EDT (Sat, 28 Apr 2012)
@@ -75,11 +75,6 @@
 t.write("Jamroot.jam", """
 import common ;
 
-actions copy {
- sleep 1
- cp $(>) $(<)
-}
-
 make header1.h : header1.in : @common.copy ;
 make header2.h : header2.in : @common.copy ;
 make header3.h : header3.in : @common.copy ;
@@ -150,5 +145,80 @@
 t.expect_addition("bin/$toolset/debug/test.obj")
 t.expect_nothing_more()
 
+t.rm(".")
+
+# Test that all the dependencies of a loop are
+# updated before any of the dependents.
+t.write("test1.cpp", """
+#include "header1.h"
+""")
+
+t.write("test2.cpp", """
+#include "header2.h"
+
+int main() {}
+""")
+
+t.write("header1.h", """
+#ifndef HEADER1_H
+#define HEADER1_H
+#include "header2.h"
+#endif
+""")
+
+t.write("header2.h", """
+#ifndef HEADER2_H
+#define HEADER2_H
+#include "header1.h"
+#include "header3.h"
+#endif
+""")
+
+t.write("header3.in", """
+""")
+
+t.write("sleep.bat","""@setlocal
+@echo off
+@REM timeout /T %1 /NOBREAK >nul
+ping 127.0.0.1 -n 2 -w 1000 >nul
+ping 127.0.0.1 -n %1 -w 1000 >nul
+@endlocal
+@exit /B 0
+""")
+
+t.write("Jamroot.jam", """
+import common ;
+import os ;
+
+if [ os.name ] = NT
+{
+ SLEEP = call sleep.bat ;
+}
+else
+{
+ SLEEP = sleep ;
+}
+
+rule copy {
+ common.copy $(<) : $(>) ;
+}
+
+actions copy {
+ $(SLEEP) 1
+}
+
+make header3.h : header3.in : @copy ;
+exe test : test2.cpp test1.cpp :
+ <implicit-dependency>header3.h
+ ;
+""")
+
+t.run_build_system("-j2 test")
+t.expect_addition("bin/$toolset/debug/header3.h")
+t.expect_addition("bin/$toolset/debug/test1.obj")
+t.expect_addition("bin/$toolset/debug/test2.obj")
+t.expect_addition("bin/$toolset/debug/test.exe")
+t.expect_nothing_more()
+
 
 t.cleanup()


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk