int make1( TARGET *t ) { state *pState; memset( (char *)counts, 0, sizeof( *counts ) ); /* Recursively make the target and its dependents */ push_state(&state_stack, t, NULL, T_STATE_MAKE1A); do { while((pState = current_state(&state_stack)) != NULL) { if (intr) pop_state(&state_stack); switch(pState->curstate) { case T_STATE_MAKE1A: make1a(pState); break; case T_STATE_MAKE1ATAIL: make1atail(pState); break; case T_STATE_MAKE1B: make1b(pState); break; case T_STATE_MAKE1C: make1c(pState); break; case T_STATE_MAKE1D: make1d(pState); break; default: break; } } /* Wait for any outstanding commands to finish running. */ } while( execwait() ); clear_state_freelist(); /* Talk about it */ if( counts->failed ) printf( "...failed updating %d target%s...\n", counts->failed, counts->failed > 1 ? "s" : "" ); if( DEBUG_MAKE && counts->skipped ) printf( "...skipped %d target%s...\n", counts->skipped, counts->skipped > 1 ? "s" : "" ); if( DEBUG_MAKE && counts->made ) printf( "...updated %d target%s...\n", counts->made, counts->made > 1 ? "s" : "" ); return counts->total != counts->made; }
int make1( TARGET * const t ) { state * pState; memset( (char *)counts, 0, sizeof( *counts ) ); /* Recursively make the target and its dependencies. */ push_state( &state_stack, t, NULL, T_STATE_MAKE1A ); while ( 1 ) { while ( ( pState = current_state( &state_stack ) ) ) { if ( intr ) pop_state( &state_stack ); switch ( pState->curstate ) { case T_STATE_MAKE1A: make1a( pState ); break; case T_STATE_MAKE1B: make1b( pState ); break; case T_STATE_MAKE1C: make1c( pState ); break; default: assert( !"make1(): Invalid state detected." ); } } if ( !cmdsrunning ) break; /* Wait for outstanding commands to finish running. */ exec_wait(); } clear_state_freelist(); /* Talk about it. */ if ( counts->failed ) printf( "...failed updating %d target%s...\n", counts->failed, counts->failed > 1 ? "s" : "" ); if ( DEBUG_MAKE && counts->skipped ) printf( "...skipped %d target%s...\n", counts->skipped, counts->skipped > 1 ? "s" : "" ); if ( DEBUG_MAKE && counts->made ) printf( "...updated %d target%s...\n", counts->made, counts->made > 1 ? "s" : "" ); return counts->total != counts->made; }
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 make1d( #ifdef OPT_SERIAL_OUTPUT_EXT const char* outputname, #endif void *closure, int status ) { TARGET *t = (TARGET *)closure; CMD *cmd = (CMD *)t->cmds; #ifdef OPT_DEBUG_MAKE1_LOG_EXT if (DEBUG_MAKE1) { printf( "make1d\t--\t%s\n" , t->name ); } #endif /* Execcmd() has completed. All we need to do is fiddle with the */ /* status and signal our completion so make1c() can run the next */ /* command. On interrupts, we bail heavily. */ if( status == EXEC_CMD_FAIL && ( cmd->rule->flags & RULE_IGNORE ) ) status = EXEC_CMD_OK; /* On interrupt, set intr so _everything_ fails */ if( status == EXEC_CMD_INTR ) ++intr; #ifndef OPT_SERIAL_OUTPUT_EXT if( status == EXEC_CMD_FAIL && DEBUG_MAKE ) { /* Print command text on failure */ if( !DEBUG_EXEC ) printf( "%s\n", buffer_ptr( &cmd->commandbuff ) ); #ifdef OPT_RESPONSE_FILES if (!DEBUG_EXEC) { printResponseFiles(cmd); } #endif printf( "*** failed %s ", cmd->rule->name ); list_print( lol_get( &cmd->args, 0 ) ); printf( "...\n" ); if( globs.quitquick ) ++intr; } #else if( DEBUG_MAKE ) { if( DEBUG_MAKEQ || ! ( cmd->rule->flags & RULE_QUIETLY ) ) { #ifdef OPT_PERCENT_DONE_EXT /* CWM - added '@' and %done to front of output */ int done = counts->skipped + counts->failed + counts->made; float percent = (done * 99.0f) / globs.updating; printf( "@ %2.0f%% %s ", percent, cmd->rule->name ); #else /* CWM - Added '@' to front of output */ printf( "@ %s ", cmd->rule->name ); #endif #ifdef OPT_DEBUG_MAKE_PRINT_TARGET_NAME if (globs.printtarget) { printf("%s ", t->name); } else { list_print( lol_get( &cmd->args, 0 ) ); } #else list_print( lol_get( &cmd->args, 0 ) ); #endif printf( "\n" ); } } if( DEBUG_EXEC || (status == EXEC_CMD_FAIL && DEBUG_MAKE) ) { printf( "%s\n", buffer_ptr(&cmd->commandbuff) ); #ifdef OPT_RESPONSE_FILES printResponseFiles(cmd); #endif } /* Print the output now, if there was any */ if( outputname ) { FILE *fp; size_t n; char buf[4096]; fp = fopen( outputname, "r" ); if (fp) { n = fread(buf, sizeof(char), sizeof buf, fp); // if (verifyIsRealOutput (buf, n)) { fwrite(buf, sizeof(char), n, stdout); n = fread(buf, sizeof(char), sizeof buf, fp); while (n > 0) { fwrite(buf, sizeof(char), n, stdout); n = fread(buf, sizeof(char), sizeof buf, fp); } } fclose(fp); } } if( status == EXEC_CMD_FAIL && DEBUG_MAKE ) { printf( "*** failed %s ", cmd->rule->name ); #ifdef OPT_DEBUG_MAKE_PRINT_TARGET_NAME if (globs.printtarget) { printf("%s ", t->name); } else { list_print( lol_get( &cmd->args, 0 ) ); } #else list_print( lol_get( &cmd->args, 0 ) ); #endif printf( "...\n" ); if (globs.quitquick) { ++intr; } } #endif /* OPT_SERIAL_OUTPUT_EXT */ /* If the command was interrupted or failed and the target */ /* is not "precious", remove the targets. */ /* Precious == 'actions updated' -- the target maintains state. */ if( status != EXEC_CMD_OK ) { if ( !( cmd->rule->flags & RULE_UPDATED ) ) { LIST *targets = lol_get( &cmd->args, 0 ); #ifdef OPT_NODELETE_READONLY for( ; targets; targets = list_next( targets ) ) if( file_writeable( targets->string ) && !unlink( targets->string ) ) printf( "*** removing %s\n", targets->string ); #else for( ; targets; targets = list_next( targets ) ) if( !unlink( targets->string ) ) printf( "*** removing %s\n", targets->string ); #endif } } #ifdef OPT_BUILTIN_MD5CACHE_EXT else { LIST *targets = lol_get( &cmd->args, 0 ); for( ; targets; targets = list_next( targets ) ) { TARGET *t = bindtarget( targets->string ); filecache_update( t ); } } #endif /* Free this command and call make1c() to move onto next command. */ t->status = (char)status; t->cmds = (char *)cmd_next( cmd ); cmd_free( cmd ); make1c( t ); }
int make1( LIST * targets ) { state * pState; int status = 0; memset( (char *)counts, 0, sizeof( *counts ) ); { LISTITER iter, end; stack temp_stack = { NULL }; for ( iter = list_begin( targets ), end = list_end( targets ); iter != end; iter = list_next( iter ) ) push_state( &temp_stack, bindtarget( list_item( iter ) ), NULL, T_STATE_MAKE1A ); push_stack_on_stack( &state_stack, &temp_stack ); } /* Clear any state left over from the past */ quit = 0; /* Recursively make the target and its dependencies. */ while ( 1 ) { while ( ( pState = current_state( &state_stack ) ) ) { if ( quit ) pop_state( &state_stack ); switch ( pState->curstate ) { case T_STATE_MAKE1A: make1a( pState ); break; case T_STATE_MAKE1B: make1b( pState ); break; case T_STATE_MAKE1C: make1c( pState ); break; default: assert( !"make1(): Invalid state detected." ); } } if ( !cmdsrunning ) break; /* Wait for outstanding commands to finish running. */ exec_wait(); } clear_state_freelist(); /* Talk about it. */ if ( counts->failed ) printf( "...failed updating %d target%s...\n", counts->failed, counts->failed > 1 ? "s" : "" ); if ( DEBUG_MAKE && counts->skipped ) printf( "...skipped %d target%s...\n", counts->skipped, counts->skipped > 1 ? "s" : "" ); if ( DEBUG_MAKE && counts->made ) printf( "...updated %d target%s...\n", counts->made, counts->made > 1 ? "s" : "" ); /* If we were interrupted, exit now that all child processes have finished. */ if ( intr ) exit( 1 ); { LISTITER iter, end; for ( iter = list_begin( targets ), end = list_end( targets ); iter != end; iter = list_next( iter ) ) { /* Check that the target was updated and that the update succeeded. */ TARGET * t = bindtarget( list_item( iter ) ); if (t->progress == T_MAKE_DONE) { if (t->status != EXEC_CMD_OK) status = 1; } else if ( ! ( t->progress == T_MAKE_NOEXEC_DONE && globs.noexec ) ) { status = 1; } } } return status; }