static void make1b( state *pState ) { TARGET *t = pState->t; TARGETS *c; TARGET *failed = 0; char* failed_name = "dependencies"; /* If any dependents are still outstanding, wait until they */ /* call make1b() to signal their completion. */ if( --(pState->t->asynccnt) ) { pop_state(&state_stack); return; } /* Try to aquire a semaphore. If it's locked, wait until the target that locked it is build and signals completition. */ #ifdef OPT_SEMAPHORE if( t->semaphore && t->semaphore->asynccnt ) { /* Append 't' to the list of targets waiting on semaphore. */ t->semaphore->parents = targetentry( t->semaphore->parents, t ); t->asynccnt++; if( DEBUG_EXECCMD ) printf( "SEM: %s is busy, delaying launch of %s\n", t->semaphore->name, t->name); pop_state(&state_stack); return; } #endif /* Now ready to build target 't'... if dependents built ok. */ /* Collect status from dependents */ for( c = t->depends; c; c = c->next ) if( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE )) { failed = c->target; pState->t->status = c->target->status; } /* If a internal header node failed to build, we'd want to output the target that it failed on. */ if (failed && (failed->flags & T_FLAG_INTERNAL)) { failed_name = failed->failed; } else if (failed) { failed_name = failed->name; } t->failed = failed_name; /* If actions on deps have failed, bail. */ /* Otherwise, execute all actions to make target */ if( pState->t->status == EXEC_CMD_FAIL && pState->t->actions ) { ++counts->skipped; if ( ( pState->t->flags & ( T_FLAG_RMOLD | T_FLAG_NOTFILE ) ) == T_FLAG_RMOLD ) { if( !unlink( pState->t->boundname ) ) printf( "...removing outdated %s\n", pState->t->boundname ); } else { printf( "...skipped %s for lack of %s...\n", pState->t->name, failed_name ); } } if( pState->t->status == EXEC_CMD_OK ) switch( pState->t->fate ) { /* These are handled by the default case below now case T_FATE_INIT: case T_FATE_MAKING: */ case T_FATE_STABLE: case T_FATE_NEWER: break; case T_FATE_CANTFIND: case T_FATE_CANTMAKE: pState->t->status = EXEC_CMD_FAIL; break; case T_FATE_ISTMP: if( DEBUG_MAKE ) printf( "...using %s...\n", pState->t->name ); break; case T_FATE_TOUCHED: case T_FATE_MISSING: case T_FATE_NEEDTMP: case T_FATE_OUTDATED: case T_FATE_UPDATE: case T_FATE_REBUILD: /* Set "on target" vars, build actions, unset vars */ /* Set "progress" so that make1c() counts this target among */ /* the successes/failures. */ if( pState->t->actions ) { ++counts->total; if( DEBUG_MAKE && !( counts->total % 100 ) ) printf( "...on %dth target...\n", counts->total ); pState->t->cmds = (char *)make1cmds( pState->t ); pState->t->progress = T_MAKE_RUNNING; } break; /* All possible fates should have been accounted for by now */ default: printf("ERROR: %s has bad fate %d", pState->t->name, pState->t->fate); abort(); } /* Call make1c() to begin the execution of the chain of commands */ /* needed to build target. If we're not going to build target */ /* (because of dependency failures or because no commands need to */ /* be run) the chain will be empty and make1c() will directly */ /* signal the completion of target. */ /* Recurse on our dependents, manipulating progress to guard */ #ifdef OPT_SEMAPHORE /* If there is a semaphore, indicate that its in use */ if( pState->t->semaphore ) { ++(pState->t->semaphore->asynccnt); if( DEBUG_EXECCMD ) printf( "SEM: %s now used by %s\n", pState->t->semaphore->name, pState->t->name ); } #endif pState->curstate = T_STATE_MAKE1C; }
static void make1b( TARGET *t ) { TARGETS *c; const char *failed; #ifdef OPT_MULTIPASS_EXT int missing; #endif #ifdef OPT_BUILTIN_NEEDS_EXT int childmightnotupdate; int childscancontents; int childupdated; #endif #ifdef OPT_DEBUG_MAKE1_LOG_EXT if (DEBUG_MAKE1) { printf( "make1b\t--\t%s (asynccnt %d)\n" , t->name, t->asynccnt); } #endif /* If any dependents are still outstanding, wait until they */ /* call make1b() to signal their completion. */ if( --t->asynccnt ) return; #ifdef OPT_INTERRUPT_FIX if( intr ) return; #endif failed = "dependents"; #ifdef OPT_MULTIPASS_EXT missing = 0; #endif #ifdef OPT_BUILTIN_NEEDS_EXT childmightnotupdate = 0; childscancontents = 0; childupdated = 0; #endif #ifdef OPT_SEMAPHORE if( t->semaphore && t->semaphore->asynccnt ) { /* We can't launch yet. Try again when the semaphore is free */ #ifdef OPT_BUILTIN_NEEDS_EXT t->semaphore->parents = targetentry( t->semaphore->parents, t, 0 ); #else t->semaphore->parents = targetentry( t->semaphore->parents, t ); #endif t->asynccnt++; if( DEBUG_EXECCMD ) printf( "SEM: %s is busy, delaying launch of %s\n", t->semaphore->name, t->name); return; } #endif /* Now ready to build target 't'... if dependents built ok. */ /* Collect status from dependents */ for( c = t->depends; c; c = c->next ) { if ( !(t->flags & T_FLAG_INTERNAL) && c->target->asynccnt ) { // printf("warning: Trying to build '%s' before dependent '%s' is done!\n", t->name, c->target->name); } #ifdef OPT_BUILTIN_NEEDS_EXT /* Only test a target's MightNotUpdate flag if the target's build was successful. */ if( c->target->status == EXEC_CMD_OK ) { if ( c->target->flags & T_FLAG_MIGHTNOTUPDATE ) { time_t timestamp; /* Mark that we've seen a MightNotUpdate flag in this set of children. */ childmightnotupdate = 1; /* Grab the generated target's timestamp. */ if ( file_time( c->target->boundname, ×tamp ) == 0 ) { /* If the child's timestamp is greater that the target's timestamp, then it updated. */ if ( timestamp > t->time ) { if ( c->target->flags & T_FLAG_SCANCONTENTS ) { childscancontents = 1; if ( getcachedmd5sum( c->target, 1 ) ) childupdated = 1; } else childupdated = 1; } else { childscancontents = 1; } } } /* If it didn't have the MightNotUpdate flag but did update, mark it. */ else if ( c->target->fate > T_FATE_STABLE && !c->needs ) { if ( c->target->flags & T_FLAG_SCANCONTENTS ) { childscancontents = 1; if ( getcachedmd5sum( c->target, 1 ) ) childupdated = 1; } else childupdated = 1; } } #endif if( c->target->status > t->status ) { failed = c->target->name; t->status = c->target->status; #ifdef OPT_MULTIPASS_EXT if ( ( c->target->fate == T_FATE_MISSING && ! ( c->target->flags & T_FLAG_NOCARE ) && !c->target->actions ) || t->status == EXEC_CMD_NEXTPASS ) { missing = 1; if ( queuedjamfiles ) { ACTIONS *actions; t->status = EXEC_CMD_NEXTPASS; for( actions = t->actions; actions; actions = actions->next ) { actions->action->pass++; } } } #endif } #ifdef OPT_NOCARE_NODES_EXT /* CWM */ /* If actions on deps have failed, but if this is a 'nocare' target */ /* then continue anyway. */ if( ( t->flags & T_FLAG_NOCARE ) && t->status == EXEC_CMD_FAIL ) { printf( "...dependency on %s failed, but don't care...\n", t->name ); t->status = EXEC_CMD_OK; } #endif } #ifdef OPT_BUILTIN_NEEDS_EXT /* If we found a MightNotUpdate flag and there was an update, mark the fate as updated. */ if ( childmightnotupdate && childupdated && t->fate == T_FATE_STABLE ) t->fate = T_FATE_UPDATE; if ( childscancontents ) { if ( !childupdated ) { if ( t->includes ) { for( c = t->includes->depends; c; c = c->next ) { if ( c->target->fate > T_FATE_STABLE && !c->needs ) { if ( c->target->flags & T_FLAG_SCANCONTENTS ) { if ( getcachedmd5sum( c->target, 1 ) || !md5matchescommandline( c->target ) ) { childupdated = 1; break; } } else { childupdated = 1; break; } } } } if ( !childupdated ) t->fate = T_FATE_STABLE; } else if ( t->fate == T_FATE_STABLE ) t->fate = T_FATE_UPDATE; } if ( t->fate == T_FATE_UPDATE && !childupdated && t->status != EXEC_CMD_NEXTPASS ) if ( md5matchescommandline( t ) ) t->fate = T_FATE_STABLE; if ( t->flags & ( T_FLAG_MIGHTNOTUPDATE | T_FLAG_SCANCONTENTS ) && t->actions ) { #ifdef OPT_ACTIONS_WAIT_FIX /* See http://maillist.perforce.com/pipermail/jamming/2003-December/002252.html */ /* Determine if an action is already running on behalf of another target, and if so, */ /* bail out of make1b() prior to calling make1cmds() by adding more parents to the */ /* in-progress target and incrementing the asynccnt of the new target. */ make1wait( t ); if ( t->asynccnt != 0 ) return; #endif } #endif /* If actions on deps have failed, bail. */ /* Otherwise, execute all actions to make target */ #ifdef OPT_MULTIPASS_EXT if( t->status == EXEC_CMD_FAIL && t->actions && !missing ) #else if( t->status == EXEC_CMD_FAIL && t->actions ) #endif { ++counts->skipped; printf( "*** skipped %s for lack of %s...\n", t->name, failed ); } if( t->status == EXEC_CMD_OK ) switch( t->fate ) { case T_FATE_INIT: case T_FATE_MAKING: /* shouldn't happen */ case T_FATE_STABLE: case T_FATE_NEWER: break; case T_FATE_CANTFIND: case T_FATE_CANTMAKE: t->status = EXEC_CMD_FAIL; break; case T_FATE_ISTMP: if( DEBUG_MAKEQ ) printf( "*** using %s...\n", t->name ); break; case T_FATE_TOUCHED: case T_FATE_MISSING: case T_FATE_NEEDTMP: case T_FATE_OUTDATED: case T_FATE_UPDATE: /* Set "on target" vars, build actions, unset vars */ /* Set "progress" so that make1c() counts this target among */ /* the successes/failures. */ #ifdef OPT_DEBUG_MAKE1_LOG_EXT if (DEBUG_MAKE1) { printf( "make1b\t--\t%s (has actions)\n" , t->name ); } #endif if( t->actions ) { #ifdef OPT_ACTIONS_WAIT_FIX /* See http://maillist.perforce.com/pipermail/jamming/2003-December/002252.html */ /* Determine if an action is already running on behalf of another target, and if so, */ /* bail out of make1b() prior to calling make1cmds() by adding more parents to the */ /* in-progress target and incrementing the asynccnt of the new target. */ make1wait( t ); if ( t->asynccnt != 0 ) return; #endif ++counts->total; #ifndef OPT_IMPROVED_PROGRESS_EXT if( DEBUG_MAKE && !( counts->total % 100 ) ) printf( "*** on %dth target...\n", counts->total ); #else { double est_remaining; est_remaining = progress_update(globs.progress, counts->total); if (est_remaining > 0) { int minutes = (int)est_remaining / 60; int seconds = (int)est_remaining % 60; if (minutes > 0 || seconds > 0) { printf("*** completed %.0f%% (", ((double)counts->total * 100 / globs.updating)); if (minutes > 0) printf("%d min ", minutes); if (seconds >= 0) printf("%d sec ", seconds); printf("remaining)...\n"); } } } #endif #ifdef OPT_BUILTIN_MD5CACHE_EXT pushsettings( t->settings ); filecache_fillvalues( t ); popsettings( t->settings ); t->cmds = (char *)make1cmds( t, t->actions ); #else pushsettings( t->settings ); t->cmds = (char *)make1cmds( t->actions ); popsettings( t->settings ); #endif t->progress = T_MAKE_RUNNING; } break; } #ifdef OPT_SEMAPHORE /* If there is a semaphore, indicate that its in use */ if( t->semaphore ) { ++(t->semaphore->asynccnt); if( DEBUG_EXECCMD ) printf( "SEM: %s now used by %s\n", t->semaphore->name, t->name ); } #endif /* Call make1c() to begin the execution of the chain of commands */ /* needed to build target. If we're not going to build target */ /* (because of dependency failures or because no commands need to */ /* be run) the chain will be empty and make1c() will directly */ /* signal the completion of target. */ make1c( t ); }
static void make1b( state * const pState ) { TARGET * const t = pState->t; TARGET * failed = 0; char const * failed_name = "dependencies"; /* If any dependencies are still outstanding, wait until they signal their * completion by pushing this same state for their parent targets. */ if ( --t->asynccnt ) { pop_state( &state_stack ); return; } /* Try to aquire a semaphore. If it is locked, wait until the target that * locked it is built and signals completition. */ #ifdef OPT_SEMAPHORE if ( t->semaphore && t->semaphore->asynccnt ) { /* Append 't' to the list of targets waiting on semaphore. */ t->semaphore->parents = targetentry( t->semaphore->parents, t ); t->asynccnt++; if ( DEBUG_EXECCMD ) printf( "SEM: %s is busy, delaying launch of %s\n", object_str( t->semaphore->name ), object_str( t->name ) ); pop_state( &state_stack ); return; } #endif /* Now ready to build target 't', if dependencies built OK. */ /* Collect status from dependencies. If -n was passed then act as though all * dependencies built correctly (the only way they can fail is if UPDATE_NOW * was called). If the dependencies can not be found or we got an interrupt, * we can not get here. */ if ( !globs.noexec ) { TARGETS * c; for ( c = t->depends; c; c = c->next ) if ( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ) ) { failed = c->target; t->status = c->target->status; } } /* If an internal header node failed to build, we want to output the target * that it failed on. */ if ( failed ) failed_name = failed->flags & T_FLAG_INTERNAL ? failed->failed : object_str( failed->name ); t->failed = failed_name; /* If actions for building any of the dependencies have failed, bail. * Otherwise, execute all actions to make the current target. */ if ( ( t->status == EXEC_CMD_FAIL ) && t->actions ) { ++counts->skipped; if ( ( t->flags & ( T_FLAG_RMOLD | T_FLAG_NOTFILE ) ) == T_FLAG_RMOLD ) { if ( !unlink( object_str( t->boundname ) ) ) printf( "...removing outdated %s\n", object_str( t->boundname ) ); } else printf( "...skipped %s for lack of %s...\n", object_str( t->name ), failed_name ); } if ( t->status == EXEC_CMD_OK ) switch ( t->fate ) { case T_FATE_STABLE: case T_FATE_NEWER: break; case T_FATE_CANTFIND: case T_FATE_CANTMAKE: t->status = EXEC_CMD_FAIL; break; case T_FATE_ISTMP: if ( DEBUG_MAKE ) printf( "...using %s...\n", object_str( t->name ) ); break; case T_FATE_TOUCHED: case T_FATE_MISSING: case T_FATE_NEEDTMP: case T_FATE_OUTDATED: case T_FATE_UPDATE: case T_FATE_REBUILD: /* Prepare commands for executing actions scheduled for this target. * Commands have their embedded variables automatically expanded, * including making use of any "on target" variables. */ if ( t->actions ) { ++counts->total; if ( DEBUG_MAKE && !( counts->total % 100 ) ) printf( "...on %dth target...\n", counts->total ); t->cmds = (char *)make1cmds( t ); /* Update the target's "progress" so MAKE1C processing counts it * among its successes/failures. */ t->progress = T_MAKE_RUNNING; } break; /* All valid fates should have been accounted for by now. */ default: printf( "ERROR: %s has bad fate %d", object_str( t->name ), t->fate ); abort(); } #ifdef OPT_SEMAPHORE /* If there is a semaphore, indicate that it is in use. */ if ( t->semaphore ) { ++t->semaphore->asynccnt; if ( DEBUG_EXECCMD ) printf( "SEM: %s now used by %s\n", object_str( t->semaphore->name ), object_str( t->name ) ); } #endif /* Proceed to MAKE1C to begin executing the chain of commands prepared for * building the target. If we are not going to build the target (e.g. due to * dependency failures or no commands needing to be run) the chain will be * empty and MAKE1C processing will directly signal the target's completion. */ /* Implementation note: * Morfing the current state on the stack instead of popping it and * pushing a new one is a slight optimization with no side-effects since we * pushed no other states while processing this one. */ pState->curstate = T_STATE_MAKE1C; }
static void make1b( state * const pState ) { TARGET * const t = pState->t; TARGET * failed = 0; char const * failed_name = "dependencies"; pop_state( &state_stack ); /* If any dependencies are still outstanding, wait until they signal their * completion by pushing this same state for their parent targets. */ if ( --t->asynccnt ) { return; } /* Now ready to build target 't', if dependencies built OK. */ /* Collect status from dependencies. If -n was passed then act as though all * dependencies built correctly (the only way they can fail is if UPDATE_NOW * was called). If the dependencies can not be found or we got an interrupt, * we can not get here. */ if ( !globs.noexec ) { TARGETS * c; for ( c = t->depends; c; c = c->next ) if ( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ) ) { failed = c->target; t->status = c->target->status; } } /* If an internal header node failed to build, we want to output the target * that it failed on. */ if ( failed ) failed_name = failed->flags & T_FLAG_INTERNAL ? failed->failed : object_str( failed->name ); t->failed = failed_name; /* If actions for building any of the dependencies have failed, bail. * Otherwise, execute all actions to make the current target. */ if ( ( t->status == EXEC_CMD_FAIL ) && t->actions ) { ++counts->skipped; if ( ( t->flags & ( T_FLAG_RMOLD | T_FLAG_NOTFILE ) ) == T_FLAG_RMOLD ) { if ( !unlink( object_str( t->boundname ) ) ) printf( "...removing outdated %s\n", object_str( t->boundname ) ); } else printf( "...skipped %s for lack of %s...\n", object_str( t->name ), failed_name ); } if ( t->status == EXEC_CMD_OK ) switch ( t->fate ) { case T_FATE_STABLE: case T_FATE_NEWER: break; case T_FATE_CANTFIND: case T_FATE_CANTMAKE: t->status = EXEC_CMD_FAIL; break; case T_FATE_ISTMP: if ( DEBUG_MAKE ) printf( "...using %s...\n", object_str( t->name ) ); break; case T_FATE_TOUCHED: case T_FATE_MISSING: case T_FATE_NEEDTMP: case T_FATE_OUTDATED: case T_FATE_UPDATE: case T_FATE_REBUILD: /* Prepare commands for executing actions scheduled for this target. * Commands have their embedded variables automatically expanded, * including making use of any "on target" variables. */ if ( t->actions ) { ++counts->total; if ( DEBUG_MAKE && !( counts->total % 100 ) ) printf( "...on %dth target...\n", counts->total ); t->cmds = (char *)make1cmds( t ); /* Update the target's "progress" so MAKE1C processing counts it * among its successes/failures. */ t->progress = T_MAKE_RUNNING; } break; /* All valid fates should have been accounted for by now. */ default: printf( "ERROR: %s has bad fate %d", object_str( t->name ), t->fate ); abort(); } /* Proceed to MAKE1C to begin executing the chain of commands prepared for * building the target. If we are not going to build the target (e.g. due to * dependency failures or no commands needing to be run) the chain will be * empty and MAKE1C processing will directly signal the target's completion. */ if ( t->cmds == NULL || --( ( CMD * )t->cmds )->asynccnt == 0 ) push_state( &state_stack, t, NULL, T_STATE_MAKE1C ); else if ( DEBUG_EXECCMD ) { CMD * cmd = ( CMD * )t->cmds; printf( "Delaying %s %s: %d targets not ready\n", object_str( cmd->rule->name ), object_str( t->boundname ), cmd->asynccnt ); } }