2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-16 01:12:13 +00:00

Handle cycles when determining target fate in make0.

[SVN r78259]
This commit is contained in:
Steven Watanabe
2012-04-30 01:21:04 +00:00
parent fbc3382f18
commit 49c19f649f
5 changed files with 87 additions and 33 deletions

View File

@@ -280,6 +280,7 @@ void make0
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 @@ void make0
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 @@ void make0
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.
*/

View File

@@ -76,7 +76,6 @@ static SETTINGS * make1settings( struct module_t * module, LIST * vars );
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 @@ int make1( TARGET * t )
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 @@ static void make1a( state * pState )
* 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 @@ static void make1a( state * pState )
* 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 @@ static void make1a( state * pState )
}
/* 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 @@ static void make1c( state * pState )
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 @@ 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 );
TARGET * other_root = target_scc( t );
if ( other_root != scc_root )
{
other_root->scc_root = scc_root;
@@ -1271,25 +1276,10 @@ static TARGET * make1findcycle( TARGET * t )
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;
}

View File

@@ -214,6 +214,26 @@ void touch_target( OBJECT * t )
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.

View File

@@ -228,6 +228,7 @@ struct _target
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 @@ void target_include ( TARGET * including, TARGET * included
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();

View File

@@ -220,6 +220,14 @@ t.expect_addition("bin/$toolset/debug/test2.obj")
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