$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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