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

Replace ad hoc (incorrect) cycle detection code with a variation of Tarjan's algorithm.

[SVN r78287]
This commit is contained in:
Steven Watanabe
2012-05-01 06:45:35 +00:00
parent e7e546092b
commit 64add142e1
5 changed files with 77 additions and 130 deletions

View File

@@ -509,7 +509,14 @@ LIST * builtin_depends( FRAME * frame, int flags )
for ( ; iter != end; iter = list_next( iter ) )
{
TARGET * s = bindtarget( list_item( iter ) );
s->dependants = targetlist( s->dependants, targets );
if ( flags )
{
LISTITER t_iter = list_begin( targets ), t_end = list_end( targets );
for ( ; t_iter != t_end; t_iter = list_next( t_iter ) )
s->dependants = targetentry( s->dependants, bindtarget( list_item( t_iter ) )->includes );
}
else
s->dependants = targetlist( s->dependants, targets );
}
return L0;

View File

@@ -129,7 +129,7 @@ int make( LIST * targets, int anyhow )
{
TARGET * t = bindtarget( list_item( iter ) );
if ( t->fate == T_FATE_INIT )
make0( t, 0, 0, counts, anyhow );
make0( t, 0, 0, counts, anyhow, 0 );
}
PROFILE_EXIT( MAKE_MAKE0 );
}
@@ -240,6 +240,48 @@ static void force_rebuilds( TARGET * t )
}
int make0rescan( TARGET * t, TARGET * rescanning )
{
int result = 0;
TARGETS * c;
/* Check whether we've already found a cycle. */
if( target_scc( t ) == rescanning )
{
return 1;
}
/* If we've already visited this node, ignore it. */
if ( t->rescanning == rescanning )
return 0;
/* If t is already updated, ignore it. */
if ( t->scc_root == NULL &&
t->progress != T_MAKE_INIT &&
t->progress != T_MAKE_ONSTACK &&
t->progress != T_MAKE_ACTIVE )
return 0;
t->rescanning = rescanning;
for ( c = t->depends; c; c = c->next )
{
TARGET * dependency = c->target;
/* Always start at the root of each new strongly connected component. */
if ( target_scc( dependency ) != target_scc( t ) )
dependency = target_scc( dependency );
result |= make0rescan( dependency, rescanning );
/* Make sure that we pick up the new include node. */
if ( c->target->includes == rescanning )
result = 1;
}
if ( result && t->scc_root == NULL )
{
t->scc_root = rescanning;
rescanning->depends = targetentry( rescanning->depends, t );
}
return result;
}
/*
* make0() - bind and scan everything to make a TARGET.
*
@@ -253,7 +295,8 @@ void make0
TARGET * p, /* parent */
int depth, /* for display purposes */
COUNTS * counts, /* for reporting */
int anyhow
int anyhow,
TARGET * rescanning
) /* forcibly touch all (real) targets */
{
TARGETS * c;
@@ -303,7 +346,11 @@ void make0
* depending on us will depend on that other target as well.
*/
if ( another_target )
t->depends = targetentry( t->depends, bindtarget( another_target ) );
{
TARGET * other = bindtarget( another_target );
t->depends = targetentry( t->depends, other );
other->dependants = targetentry( other->dependants, t );
}
t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
}
@@ -380,14 +427,18 @@ void make0
* other alot.
*/
if ( c->target->fate == T_FATE_INIT )
make0( c->target, ptime, depth + 1, counts, anyhow );
make0( c->target, ptime, depth + 1, counts, anyhow, rescanning );
else if ( c->target->fate == T_FATE_MAKING && !internal )
printf( "warning: %s depends on itself\n", object_str( c->target->name ) );
else if ( c->target->fate != T_FATE_MAKING && rescanning )
make0rescan( c->target, rescanning );
if ( rescanning && c->target->includes && c->target->includes->fate != T_FATE_MAKING )
make0rescan( target_scc( c->target->includes ), rescanning );
}
/* Step 3b: recursively make0() internal includes node. */
if ( t->includes )
make0( t->includes, p, depth + 1, counts, anyhow );
make0( t->includes, p, depth + 1, counts, anyhow, rescanning );
/* Step 3c: add dependencies' includes to our direct dependencies. */
{

View File

@@ -28,7 +28,7 @@ typedef struct {
void make0( TARGET *t, TARGET *p, int depth,
COUNTS *counts, int anyhow );
COUNTS *counts, int anyhow, TARGET * rescanning );
/*

View File

@@ -87,8 +87,6 @@ static struct
int made;
} counts[ 1 ] ;
int handling_rescan;
/* Target state - remove recursive calls by just keeping track of state target
* is in.
*/
@@ -101,8 +99,7 @@ typedef struct _state
#define T_STATE_MAKE1ATAIL 1 /* make1atail() should be called */
#define T_STATE_MAKE1B 2 /* make1b() should be called */
#define T_STATE_MAKE1C 3 /* make1c() should be called */
#define T_STATE_MAKE1CTAIL 4 /* make1ctail() should be called */
#define T_STATE_MAKE1D 5 /* make1d() should be called */
#define T_STATE_MAKE1D 4 /* make1d() should be called */
int curstate; /* current state */
int status;
} state;
@@ -111,7 +108,6 @@ static void make1a ( state * );
static void make1atail ( state * );
static void make1b ( state * );
static void make1c ( state * );
static void make1ctail ( state * );
static void make1d ( state * );
static void make_closure( void * closure, int status, timing_info *, const char *, const char * );
@@ -233,7 +229,6 @@ int make1( TARGET * t )
case T_STATE_MAKE1ATAIL: make1atail( pState ); break;
case T_STATE_MAKE1B : make1b ( pState ); break;
case T_STATE_MAKE1C : make1c ( pState ); break;
case T_STATE_MAKE1CTAIL: make1ctail( pState ); break;
case T_STATE_MAKE1D : make1d ( pState ); break;
}
}
@@ -284,28 +279,19 @@ static void make1a( state * pState )
*/
if ( pState->parent )
{
TARGET * cycle_root;
switch ( t->progress )
{
case T_MAKE_ONSTACK:
if ( t->depth == handling_rescan )
{
if ( target_scc( pState->parent ) != scc_root )
make1breakcycle( pState->parent, t );
break;
}
case T_MAKE_ACTIVE:
if ( handling_rescan && ( cycle_root = make1findcycle( t ) ) )
{
make1breakcycle( pState->parent, cycle_root ); break;
}
case T_MAKE_INIT:
case T_MAKE_RUNNING:
if( t != pState->parent )
{
t->parents = targetentry( t->parents,
pState->parent );
++pState->parent->asynccnt;
TARGET * parent_scc = target_scc( pState->parent );
if( t != parent_scc )
{
t->parents = targetentry( t->parents, parent_scc );
++parent_scc->asynccnt;
}
}
}
}
@@ -338,18 +324,8 @@ static void make1a( state * pState )
*/
t->asynccnt = 1;
/* Add header nodes created during the building process. */
{
TARGETS * inc = 0;
for ( c = t->depends; c; c = c->next )
if ( c->target->rescanned && c->target->includes )
inc = targetentry( inc, c->target->includes );
t->depends = targetchain( t->depends, inc );
}
/* Guard against circular dependencies. */
t->progress = T_MAKE_ONSTACK;
t->depth = handling_rescan;
{
stack temp_stack = { NULL };
@@ -644,12 +620,12 @@ static void make1c( state * pState )
* target is built, otherwise the parent would be considered
* built before this make1a() processing has even started.
*/
make0( t->includes, t->parents->target, 0, 0, 0 );
make0( t->includes, t->parents->target, 0, 0, 0, t->includes );
/* Link the old includes on to make sure that it gets
* cleaned up correctly.
*/
t->includes->includes = saved_includes;
for ( c = t->parents; c; c = c->next )
for ( c = t->dependants; c; c = c->next )
c->target->depends = targetentry( c->target->depends,
t->includes );
/* Will be processed below. */
@@ -662,16 +638,13 @@ static void make1c( state * pState )
}
if ( additional_includes )
{
++handling_rescan;
for ( c = t->parents; c; c = c->next )
push_state( &temp_stack, additional_includes, c->target, T_STATE_MAKE1A );
push_state( &temp_stack, additional_includes, NULL, T_STATE_MAKE1CTAIL );
}
if ( t->scc_root )
{
TARGET * scc_root = target_scc( t );
assert( scc_root->progress < T_MAKE_DONE );
for ( c = t->parents; c; c = c->next )
{
if ( target_scc( c->target ) == scc_root )
@@ -724,12 +697,6 @@ static void make1c( state * pState )
}
}
static void make1ctail( state * pState )
{
--handling_rescan;
pop_state( &state_stack );
}
/*
* call_timing_rule() - Look up the __TIMING_RULE__ variable on the given
@@ -1217,80 +1184,3 @@ static void make1bind( TARGET * t )
t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
popsettings( root_module(), t->settings );
}
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 = target_scc( t );
if ( other_root != scc_root )
{
other_root->scc_root = scc_root;
other_root->parents = targetentry( other_root->parents, scc_root );
++scc_root->asynccnt;
}
}
if ( t != scc_root )
t->scc_root = scc_root;
}
static TARGET * make1findcycle_impl( TARGET * t, TARGET * scc_root )
{
TARGETS * c;
TARGET * result;
if ( t->progress == T_MAKE_ONSTACK )
if ( t->depth == handling_rescan )
return t;
else
t->progress = T_MAKE_FINDCYCLE_ONSTACK;
else if ( t->progress == T_MAKE_ACTIVE )
t->progress = T_MAKE_FINDCYCLE_ACTIVE;
else
return 0;
for ( c = t->depends; c; c = c->next )
if ( ( result = make1findcycle_impl( c->target, scc_root ) ) )
{
make1cyclenode( c->target, scc_root );
return result;
}
return 0;
}
static void make1findcycle_cleanup( TARGET * t )
{
TARGETS * c;
if ( t->progress == T_MAKE_FINDCYCLE_ACTIVE )
t->progress = T_MAKE_ACTIVE;
else if ( t->progress == T_MAKE_FINDCYCLE_ONSTACK )
t->progress = T_MAKE_ONSTACK;
else
return;
for ( c = t->depends; c; c = c->next )
make1findcycle_cleanup( c->target );
}
static TARGET * make1findcycle( TARGET * t )
{
TARGET * result = make1findcycle_impl( t, target_scc( t ) );
make1findcycle_cleanup( t );
return result;
}
static void make1breakcycle( TARGET * t, TARGET * cycle_root )
{
TARGET * scc_root = target_scc( cycle_root );
while ( t != cycle_root )
{
make1cyclenode( t, scc_root );
t = t->parents->target;
}
}

View File

@@ -212,8 +212,6 @@ struct _target
#define T_MAKE_RUNNING 3 /* make1(target) running commands */
#define T_MAKE_DONE 4 /* make1(target) done */
#define T_MAKE_NOEXEC_DONE 5 /* make1(target) done with -n in effect */
#define T_MAKE_FINDCYCLE_ONSTACK 6 /* make1(target) searching for cyclic includes after */
#define T_MAKE_FINDCYCLE_ACTIVE 7 /* rescanning a generated file. */
#ifdef OPT_SEMAPHORE
#define T_MAKE_SEMAPHORE 5 /* Special target type for semaphores */
@@ -227,7 +225,8 @@ struct _target
int asynccnt; /* child deps outstanding */
TARGETS * parents; /* used by make1() for completion */
TARGET * scc_root; /* used by make1 to resolve cyclic includes */
TARGET * scc_root; /* used by make to resolve cyclic includes */
TARGET * rescanning; /* used by make0 to mark visited targets when rescanning */
int depth; /* The depth of the target in the make0 stack. */
char * cmds; /* type-punned command list */