Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r78259 - in trunk/tools/build/v2: engine test
From: steven_at_[hidden]
Date: 2012-04-29 21:21:07


Author: steven_watanabe
Date: 2012-04-29 21:21:04 EDT (Sun, 29 Apr 2012)
New Revision: 78259
URL: http://svn.boost.org/trac/boost/changeset/78259

Log:
Handle cycles when determining target fate in make0.
Text files modified:
   trunk/tools/build/v2/engine/make.c | 34 ++++++++++++++++++++++++
   trunk/tools/build/v2/engine/make1.c | 56 ++++++++++++++++-----------------------
   trunk/tools/build/v2/engine/rules.c | 20 ++++++++++++++
   trunk/tools/build/v2/engine/rules.h | 2 +
   trunk/tools/build/v2/test/rescan_header.py | 8 +++++
   5 files changed, 87 insertions(+), 33 deletions(-)

Modified: trunk/tools/build/v2/engine/make.c
==============================================================================
--- trunk/tools/build/v2/engine/make.c (original)
+++ trunk/tools/build/v2/engine/make.c 2012-04-29 21:21:04 EDT (Sun, 29 Apr 2012)
@@ -280,6 +280,7 @@
         printf( "make\t--\t%s%s\n", spaces( depth ), object_str( t->name ) );
 
     t->fate = T_FATE_MAKING;
+ t->depth = depth;
 
     /*
      * Step 2: under the influence of "on target" variables,
@@ -397,6 +398,25 @@
         t->depends = targetchain( t->depends, incs );
     }
 
+ /* Step 3d: detect cycles. */
+ {
+ int cycle_depth = depth;
+ for ( c = t->depends; c; c = c->next )
+ {
+ TARGET * scc_root = target_scc( c->target );
+ if ( scc_root->fate == T_FATE_MAKING &&
+ ( !scc_root->includes ||
+ scc_root->includes->fate != T_FATE_MAKING ) )
+ {
+ if ( scc_root->depth < cycle_depth )
+ {
+ cycle_depth = scc_root->depth;
+ t->scc_root = scc_root;
+ }
+ }
+ }
+ }
+
     /*
      * Step 4: compute time & fate
      */
@@ -407,6 +427,20 @@
     fate = T_FATE_STABLE;
     for ( c = t->depends; c; c = c->next )
     {
+ /* If we're in a different strongly connected component,
+ * pull timestamps from the root.
+ */
+ if ( c->target->scc_root )
+ {
+ TARGET * scc_root = target_scc( c->target );
+ if ( scc_root != t->scc_root )
+ {
+ c->target->leaf = max( c->target->leaf, scc_root->leaf );
+ c->target->time = max( c->target->time, scc_root->time );
+ c->target->fate = max( c->target->fate, scc_root->fate );
+ }
+ }
+
         /* If LEAVES has been applied, we only heed the timestamps of the leaf
          * source nodes.
          */

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-29 21:21:04 EDT (Sun, 29 Apr 2012)
@@ -76,7 +76,6 @@
 static void make1bind ( TARGET * );
 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. */
 
@@ -271,31 +270,37 @@
 
 static void make1a( state * pState )
 {
- TARGET * t = pState->t;
+ TARGET * t = target_scc( pState->t );
     TARGETS * c;
 
+ if ( pState->parent == NULL || target_scc( pState->parent ) != t )
+ pState->t = t;
+ else
+ t = pState->t;
+
     /* If the parent is the first to try to build this target or this target is
      * in the make1c() quagmire, arrange for the parent to be notified when this
      * target is built.
      */
     if ( pState->parent )
     {
- TARGET * dependency = make1scc( t );
         TARGET * cycle_root;
- switch ( dependency->progress )
+ switch ( t->progress )
         {
             case T_MAKE_ONSTACK:
- make1breakcycle( pState->parent, dependency ); break;
+ if ( target_scc( pState->parent ) != t )
+ make1breakcycle( pState->parent, t );
+ break;
             case T_MAKE_ACTIVE:
- if ( handling_rescan && ( cycle_root = make1findcycle( dependency ) ) )
+ if ( handling_rescan && ( cycle_root = make1findcycle( t ) ) )
                 {
                     make1breakcycle( pState->parent, cycle_root ); break;
                 }
             case T_MAKE_INIT:
             case T_MAKE_RUNNING:
- if( dependency != pState->parent )
+ if( t != pState->parent )
                 {
- dependency->parents = targetentry( dependency->parents,
+ t->parents = targetentry( t->parents,
                         pState->parent );
                     ++pState->parent->asynccnt;
                 }
@@ -306,15 +311,15 @@
      * If the target has been previously updated with -n in
      * effect, and we're ignoring -n, update it for real.
      */
- if ( !globs.noexec && pState->t->progress == T_MAKE_NOEXEC_DONE )
+ if ( !globs.noexec && t->progress == T_MAKE_NOEXEC_DONE )
     {
- pState->t->progress = T_MAKE_INIT;
+ t->progress = T_MAKE_INIT;
     }
 
     /* If this target is already being processed then do nothing. There is no
      * need to start processing the same target all over again.
      */
- if ( pState->t->progress != T_MAKE_INIT )
+ if ( t->progress != T_MAKE_INIT )
     {
         pop_state( &state_stack );
         return;
@@ -328,7 +333,7 @@
      * processing all of our other dependencies our build might be triggerred
      * prematurely.
      */
- pState->t->asynccnt = 1;
+ t->asynccnt = 1;
 
     /* Add header nodes created during the building process. */
     {
@@ -340,12 +345,12 @@
     }
 
     /* Guard against circular dependencies. */
- pState->t->progress = T_MAKE_ONSTACK;
+ t->progress = T_MAKE_ONSTACK;
 
     {
         stack temp_stack = { NULL };
         for ( c = t->depends; c && !intr; c = c->next )
- push_state( &temp_stack, c->target, pState->t, T_STATE_MAKE1A );
+ push_state( &temp_stack, c->target, t, T_STATE_MAKE1A );
 
         /* Using stacks reverses the order of execution. Reverse it back. */
         push_stack_on_stack( &state_stack, &temp_stack );
@@ -662,10 +667,10 @@
 
             if ( t->scc_root )
             {
- TARGET * scc_root = make1scc( t );
+ TARGET * scc_root = target_scc( t );
                 for ( c = t->parents; c; c = c->next )
                 {
- if ( make1scc( c->target ) == scc_root )
+ if ( target_scc( c->target ) == scc_root )
                         push_state( &temp_stack, c->target, NULL, T_STATE_MAKE1B );
                     else
                         scc_root->parents = targetentry( scc_root->parents, c->target );
@@ -1215,7 +1220,7 @@
     /* if we intersect with another cycle we need to merge the two */
     if ( t->scc_root )
     {
- TARGET * other_root = make1scc( t );
+ TARGET * other_root = target_scc( t );
         if ( other_root != scc_root )
         {
             other_root->scc_root = scc_root;
@@ -1271,25 +1276,10 @@
 
 static void make1breakcycle( TARGET * t, TARGET * cycle_root )
 {
- TARGET * scc_root = make1scc( cycle_root );
+ TARGET * scc_root = target_scc( 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.c
==============================================================================
--- trunk/tools/build/v2/engine/rules.c (original)
+++ trunk/tools/build/v2/engine/rules.c 2012-04-29 21:21:04 EDT (Sun, 29 Apr 2012)
@@ -214,6 +214,26 @@
     bindtarget( t )->flags |= T_FLAG_TOUCHED;
 }
 
+/*
+ * target_scc() - returns the root of the strongly
+ * connected component that this target
+ * is a part of.
+ */
+TARGET * target_scc( 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;
+}
+
 
 /*
  * targetlist() - turn list of target names into a TARGET chain.

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-29 21:21:04 EDT (Sun, 29 Apr 2012)
@@ -228,6 +228,7 @@
     int asynccnt; /* child deps outstanding */
     TARGETS * parents; /* used by make1() for completion */
     TARGET * scc_root; /* used by make1 to resolve cyclic includes */
+ int depth; /* The depth of the target in the make0 stack. */
     char * cmds; /* type-punned command list */
 
     const char * failed;
@@ -265,6 +266,7 @@
 TARGETS * targetlist ( TARGETS * chain, LIST * target_names );
 void touch_target ( OBJECT * t );
 void clear_includes ( TARGET * );
+TARGET * target_scc ( TARGET * t );
 
 /* Final module cleanup. */
 void rules_done();

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-29 21:21:04 EDT (Sun, 29 Apr 2012)
@@ -220,6 +220,14 @@
 t.expect_addition("bin/$toolset/debug/test.exe")
 t.expect_nothing_more()
 
+t.touch("header3.in")
+t.run_build_system("-j2 test")
+t.expect_touch("bin/$toolset/debug/header3.h")
+t.expect_touch("bin/$toolset/debug/test1.obj")
+t.expect_touch("bin/$toolset/debug/test2.obj")
+t.expect_touch("bin/$toolset/debug/test.exe")
+t.expect_nothing_more()
+
 t.rm(".")
 
 # Test a loop that includes a generated header


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