diff -urN Jam-before/jam.c Jam-after/jam.c --- Jam-before/jam.c Thu Apr 29 10:50:06 2010 +++ Jam-after/jam.c Thu Apr 29 10:50:39 2010 @@ -220,6 +220,7 @@ { printf( "Jam %s. %s. ", VERSION, OSMINOR ); printf( "Copyright 1993-2002 Christopher Seiwald.\n" ); + printf( "Includes codependent target patch.\n" ); return EXITOK; } diff -urN Jam-before/make.c Jam-after/make.c --- Jam-before/make.c Thu Apr 29 10:50:06 2010 +++ Jam-after/make.c Thu Apr 29 10:50:39 2010 @@ -155,8 +155,9 @@ static void recur_depen(time_t time, TARGET *t) { TARGETS *c; + DEP_ITER i; - for( c = t->depends; c; c = c->next ) + for( c = DepIterBegin(&i, t, 0); c; c = DepIterNext(&i)) { if( DEBUG_TRACE && time && c->target->time > time ) { @@ -183,6 +184,7 @@ { TARGETS *c, *incs; TARGET *ptime = t; + DEP_ITER i; time_t last, leaf, hlast; int fate; const char *flag = ""; @@ -278,13 +280,13 @@ */ /* Step 3a: recursively make0() dependents */ - - for( c = t->depends; c; c = c->next ) + for( c = DepIterBegin(&i, t, 0); c; c = DepIterNext(&i)) { int internal = t->flags & T_FLAG_INTERNAL; if( DEBUG_DEPENDS ) - printf( "%s \"%s\" : \"%s\" ;\n", + printf( "%s%s \"%s\" : \"%s\" ;\n", + i.phase == 2 ? "Co" : "", // hack: in phase 2 we're processing codepends internal ? "Includes" : "Depends", t->name, c->target->name ); @@ -306,7 +308,7 @@ incs = 0; - for( c = t->depends; c; c = c->next ) + for( c = DepIterBegin(&i, t, 0); c; c = DepIterNext(&i)) if( c->target->includes ) incs = targetentry( incs, c->target->includes ); @@ -322,7 +324,7 @@ leaf = 0; fate = T_FATE_STABLE; - for( c = t->depends; c; c = c->next ) + for( c = DepIterBegin(&i, t, 0); c; c = DepIterNext(&i)) { /* If LEAVES has been applied, we only heed the timestamps of */ /* the leaf source nodes. */ @@ -443,7 +445,7 @@ /* We could insist that there are updating actions for all missing */ /* files, but if they have dependents we just pretend it's NOTFILE. */ - if( fate == T_FATE_MISSING && !t->actions && !t->depends ) + if( fate == T_FATE_MISSING && !t->actions && !DepIterBegin(&i, t, 0) ) { if( t->flags & T_FLAG_NOCARE ) { @@ -469,7 +471,7 @@ */ if( globs.newestfirst ) - t->depends = make0sort( t->depends ); + t->depends = make0sort( t->depends ); // Chuck - This doesn't work for codependent targets. Do we care? /* * Step 6: a little harmless tabulating for tracing purposes @@ -549,4 +551,55 @@ } return result; +} + + +/* + Dependency iterator stuff by Chuck. + See note in make.h +*/ + +// I like C#, and I miss yield return. This is a good approximation +#define YIELD_JUMP(labelnumber) if (_this->phase == labelnumber) goto p##labelnumber; +#define YIELD_RETURN(value, labelnumber) {_this->phase = labelnumber;return (value); p##labelnumber:;} + +TARGETS* DepIterNext(DEP_ITER* _this) +{ + // _this->phase is required to be zero on first run, ensured by DepIterBegin + + YIELD_JUMP(1); /* Depending on the context, jumps after the most recent YIELD_RETURN */ + YIELD_JUMP(2); /* There should be one for each YIELD_RETURN */ + YIELD_JUMP(3); + + /* First loop through direct dependents (Phase 1) */ + for( _this->c = _this->t->depends; _this->c; _this->c = _this->c->next ) + { + YIELD_RETURN(_this->c, 1); + } + + /* + Then go through each dependency of each target of each action + applicable to this target. (Co-dependent targets) (Phase 2) + */ + for( _this->a = _this->t->actions; _this->a; _this->a = _this->a->next) + for( _this->at = _this->a->action->targets; _this->at ; _this->at = _this->at->next) + if( _this->at->target != _this->t) // don't bother processing t, because we already did in phase 1 + { + if (_this->include_cotargets) YIELD_RETURN(_this->at, 3); + + for( _this->c = _this->at->target->depends; _this->c; _this->c = _this->c->next ) + { + YIELD_RETURN(_this->c, 2); + } + } + return 0; +} + + +TARGETS* DepIterBegin(DEP_ITER* _this, TARGET *t, int include_cotargets) +{ + _this->phase = 0; + _this->t = t; + _this->include_cotargets = include_cotargets; + return DepIterNext(_this); } diff -urN Jam-before/make.h Jam-after/make.h --- Jam-before/make.h Thu Apr 29 10:50:07 2010 +++ Jam-after/make.h Thu Apr 29 10:50:39 2010 @@ -12,3 +12,44 @@ int make( int n_targets, const char **targets, int anyhow ); int make1( TARGET *t ); + +/* + Added by Chuck - 5/25/2007 + + Dependency iterator stuff is meant to allow one to iterate through + a target's dependencies, and also though the dependencies of + targets that share an action. + + I've called these targets "co-dependent" because they are not (usually) + explicitly marked dependent in the jamfile, but because the action + cannot run before the prerequisites of all action targets are ready, + it's necessary for correct operation. + + The code is in make.c + + Use it like this: + + TARGET* t = whatever; + TARGETS* c; + DEP_ITER i; + for( c = DepIterBegin(&i, t); c; c = DepIterNext(&i)) + { + DoSomething(c->target); + } + +*/ + +struct DepIter_t +{ + TARGET *t; + TARGETS *c; + ACTIONS *a; + TARGETS *at; + int phase; + int include_cotargets; +}; +typedef struct DepIter_t DEP_ITER; + +TARGETS* DepIterBegin(DEP_ITER* _this, TARGET *t, int include_cotargets); +TARGETS* DepIterNext(DEP_ITER* _this); + diff -urN Jam-before/make1.c Jam-after/make1.c --- Jam-before/make1.c Thu Apr 29 10:50:07 2010 +++ Jam-after/make1.c Thu Apr 29 10:50:39 2010 @@ -125,6 +125,9 @@ TARGET *parent ) { TARGETS *c; + DEP_ITER i; + ACTIONS *a; + TARGETS *at; /* If the parent is the first to try to build this target */ /* or this target is in the make1c() quagmire, arrange for the */ @@ -156,7 +177,7 @@ t->progress = T_MAKE_ONSTACK; - for( c = t->depends; c && !intr; c = c->next ) + for( c = DepIterBegin(&i, t, 1); c && !intr; c = DepIterNext(&i)) make1a( c->target, t ); t->progress = T_MAKE_ACTIVE; @@ -175,6 +196,7 @@ make1b( TARGET *t ) { TARGETS *c; + DEP_ITER i; const char *failed = "dependents"; /* If any dependents are still outstanding, wait until they */ @@ -187,7 +209,7 @@ /* Collect status from dependents */ - for( c = t->depends; c; c = c->next ) + for( c = DepIterBegin(&i, t, 0); c; c = DepIterNext(&i)) if( c->target->status > t->status ) { failed = c->target->name;