📄 make1.c
字号:
void *closure, int status, timing_info* time, char *executed_command, char *command_output){ TARGET* built = (TARGET*)closure; call_timing_rule(built, time); if (DEBUG_EXECCMD) printf("%f sec system; %f sec user\n", time->system, time->user); call_action_rule(built, status, time, executed_command, command_output); push_state(&state_stack, built, NULL, T_STATE_MAKE1D)->status = status;}/* * make1d() - handle command execution completion and call back make1c() */static voidmake1d(state *pState){ TARGET *t = pState->t; CMD *cmd = (CMD *)t->cmds; int status = pState->status; /* 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 ( t->flags & T_FLAG_FAIL_EXPECTED ) { /* invert execution result when FAIL_EXPECTED was applied */ switch (status) { case EXEC_CMD_FAIL: status = EXEC_CMD_OK; break; case EXEC_CMD_OK: status = EXEC_CMD_FAIL; break; default: ; } } if( status == EXEC_CMD_FAIL && ( cmd->rule->actions->flags & RULE_IGNORE ) ) status = EXEC_CMD_OK; /* On interrupt, set intr so _everything_ fails */ if( status == EXEC_CMD_INTR ) ++intr; if( status == EXEC_CMD_FAIL && DEBUG_MAKE ) { /* Print command text on failure */ if( !DEBUG_EXEC ) printf( "%s\n", cmd->buf ); printf( "...failed %s ", cmd->rule->name ); list_print( lol_get( &cmd->args, 0 ) ); printf( "...\n" ); } if (status == EXEC_CMD_FAIL) if( globs.quitquick ) ++intr; /* If the command was interrupted or failed and the target */ /* is not "precious", remove the targets */ if( status != EXEC_CMD_OK && !( cmd->rule->actions->flags & RULE_TOGETHER ) ) { LIST *targets = lol_get( &cmd->args, 0 ); for( ; targets; targets = list_next( targets ) ) if( !unlink( targets->string ) ) printf( "...removing %s\n", targets->string ); } /* Free this command and call make1c() to move onto next command. */ t->status = status; t->cmds = (char *)cmd_next( cmd ); cmd_free( cmd ); pState->curstate = T_STATE_MAKE1C;}/* * swap_settings() - replace the settings from the current module and * target with those from the new module and target */static void swap_settings( module_t** current_module , TARGET** current_target , module_t* new_module , TARGET* new_target){ if (new_module == root_module()) new_module = 0; if (new_target == *current_target && new_module == *current_module) return; if (*current_target) popsettings( (*current_target)->settings ); if (new_module != *current_module) { if (*current_module) exit_module( *current_module ); *current_module = new_module; if (new_module) enter_module( new_module ); } *current_target = new_target; if (new_target) pushsettings( new_target->settings );}/* * make1cmds() - turn ACTIONS into CMDs, grouping, splitting, etc * * Essentially copies a chain of ACTIONs to a chain of CMDs, * grouping RULE_TOGETHER actions, splitting RULE_PIECEMEAL actions, * and handling RULE_NEWSRCS actions. The result is a chain of * CMDs which can be expanded by var_string() and executed with * execcmd(). */static CMD *make1cmds( TARGET *t ){ CMD *cmds = 0; LIST *shell = 0; module_t *settings_module = 0; TARGET *settings_target = 0; /* Step through actions */ /* Actions may be shared with other targets or grouped with */ /* RULE_TOGETHER, so actions already seen are skipped. */ ACTIONS* a0; for(a0 = t->actions ; a0; a0 = a0->next ) { RULE *rule = a0->action->rule; rule_actions *actions = rule->actions; SETTINGS *boundvars; LIST *nt, *ns; ACTIONS *a1; int start, chunk, length; /* Only do rules with commands to execute. */ /* If this action has already been executed, use saved status */ if( !actions || a0->action->running ) continue; a0->action->running = 1; /* Make LISTS of targets and sources */ /* If `execute together` has been specified for this rule, tack */ /* on sources from each instance of this rule for this target. */ nt = make1list( L0, a0->action->targets, 0 ); ns = make1list( L0, a0->action->sources, actions->flags ); if( actions->flags & RULE_TOGETHER ) for( a1 = a0->next; a1; a1 = a1->next ) if( a1->action->rule == rule && !a1->action->running ) { ns = make1list( ns, a1->action->sources, actions->flags ); a1->action->running = 1; } /* If doing only updated (or existing) sources, but none have */ /* been updated (or exist), skip this action. */ if( !ns && ( actions->flags & ( RULE_NEWSRCS | RULE_EXISTING ) ) ) { list_free( nt ); continue; } swap_settings( &settings_module, &settings_target, rule->module, t ); if (!shell) shell = var_get( "JAMSHELL" ); /* shell is per-target */ /* If we had 'actions xxx bind vars' we bind the vars now */ boundvars = make1settings( actions->bindlist ); pushsettings( boundvars ); /* * Build command, starting with all source args. * * If cmd_new returns 0, it's because the resulting command * length is > MAXLINE. In this case, we'll slowly reduce * the number of source arguments presented until it does * fit. This only applies to actions that allow PIECEMEAL * commands. * * While reducing slowly takes a bit of compute time to get * things just right, it's worth it to get as close to MAXLINE * as possible, because launching the commands we're executing * is likely to be much more compute intensive! * * Note we loop through at least once, for sourceless actions. */ start = 0; chunk = length = list_length( ns ); do { /* Build cmd: cmd_new consumes its lists. */ CMD *cmd = cmd_new( rule, list_copy( L0, nt ), list_sublist( ns, start, chunk ), list_copy( L0, shell ) ); if( cmd ) { /* It fit: chain it up. */ if( !cmds ) cmds = cmd; else cmds->tail->next = cmd; cmds->tail = cmd; start += chunk; } else if( ( actions->flags & RULE_PIECEMEAL ) && chunk > 1 ) { /* Reduce chunk size slowly. */ chunk = chunk * 9 / 10; } else { /* Too long and not splittable. */ printf( "%s actions too long (max %d):\n", rule->name, MAXLINE ); /* Tell the user what didn't fit */ cmd = cmd_new( rule, list_copy( L0, nt ), list_sublist( ns, start, chunk ), list_new( L0, newstr( "%" ) ) ); printf( cmd->buf ); exit( EXITBAD ); } } while( start < length ); /* These were always copied when used. */ list_free( nt ); list_free( ns ); /* Free the variables whose values were bound by */ /* 'actions xxx bind vars' */ popsettings( boundvars ); freesettings( boundvars ); } swap_settings( &settings_module, &settings_target, 0, 0 ); return cmds;}/* * make1list() - turn a list of targets into a LIST, for $(<) and $(>) */static LIST *make1list( LIST *l, TARGETS *targets, int flags ){ for( ; targets; targets = targets->next ) { TARGET *t = targets->target; if( t->binding == T_BIND_UNBOUND ) make1bind( t ); if ( ( flags & RULE_EXISTING ) && ( flags & RULE_NEWSRCS ) ) { if ( t->binding != T_BIND_EXISTS && t->fate <= T_FATE_STABLE) continue; } else { if( ( flags & RULE_EXISTING ) && t->binding != T_BIND_EXISTS ) continue; if( ( flags & RULE_NEWSRCS ) && t->fate <= T_FATE_STABLE ) continue; } /* Prohibit duplicates for RULE_TOGETHER */ if( flags & RULE_TOGETHER ) { LIST *m; for( m = l; m; m = m->next ) if( !strcmp( m->string, t->boundname ) ) break; if( m ) continue; } /* Build new list */ l = list_new( l, copystr( t->boundname ) ); } return l;}/* * make1settings() - for vars that get bound values, build up replacement lists */static SETTINGS *make1settings( LIST *vars ){ SETTINGS *settings = 0; for( ; vars; vars = list_next( vars ) ) { LIST *l = var_get( vars->string ); LIST *nl = 0; for( ; l; l = list_next( l ) ) { TARGET *t = bindtarget( l->string ); /* Make sure the target is bound */ if( t->binding == T_BIND_UNBOUND ) make1bind( t ); /* Build new list */ nl = list_new( nl, copystr( t->boundname ) ); } /* Add to settings chain */ settings = addsettings( settings, VAR_SET, vars->string, nl ); } return settings;}/* * make1bind() - bind targets that weren't bound in dependency analysis * * Spot the kludge! If a target is not in the dependency tree, it didn't * get bound by make0(), so we have to do it here. Ugly. */static voidmake1bind( TARGET *t ){ if( t->flags & T_FLAG_NOTFILE ) return; pushsettings( t->settings ); t->boundname = search( t->name, &t->time, 0 ); t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING; popsettings( t->settings );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -