diff --git a/src/engine/builtins.c b/src/engine/builtins.c index 07eaa1534..fb4cdb9c3 100644 --- a/src/engine/builtins.c +++ b/src/engine/builtins.c @@ -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; diff --git a/src/engine/make.c b/src/engine/make.c index bd4fc4706..d16e81e81 100644 --- a/src/engine/make.c +++ b/src/engine/make.c @@ -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. */ { diff --git a/src/engine/make.h b/src/engine/make.h index e0c790658..cc28ea581 100644 --- a/src/engine/make.h +++ b/src/engine/make.h @@ -28,7 +28,7 @@ typedef struct { void make0( TARGET *t, TARGET *p, int depth, - COUNTS *counts, int anyhow ); + COUNTS *counts, int anyhow, TARGET * rescanning ); /* diff --git a/src/engine/make1.c b/src/engine/make1.c index 2cacf38c0..638a4e96a 100644 --- a/src/engine/make1.c +++ b/src/engine/make1.c @@ -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; - } -} diff --git a/src/engine/rules.h b/src/engine/rules.h index f38e2a2b7..f92956624 100644 --- a/src/engine/rules.h +++ b/src/engine/rules.h @@ -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 */