|
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