static Job * prepare_job(GNode *gn, int flags) { bool cmdsOK; /* true if the nodes commands were all right */ bool noExec; /* Set true if we decide not to run the job */ /* * Check the commands now so any attributes from .DEFAULT have a chance * to migrate to the node */ cmdsOK = Job_CheckCommands(gn); expand_commands(gn); if ((gn->type & OP_MAKE) || (!noExecute && !touchFlag)) { /* * We're serious here, but if the commands were bogus, we're * also dead... */ if (!cmdsOK) job_failure(gn, Punt); if (Lst_IsEmpty(&gn->commands)) noExec = true; else noExec = false; } else if (noExecute) { if (!cmdsOK || Lst_IsEmpty(&gn->commands)) noExec = true; else noExec = false; } else { /* * Just touch the target and note that no shell should be * executed. Check * the commands, too, but don't die if they're no good -- it * does no harm to keep working up the graph. */ Job_Touch(gn); noExec = true; } /* * If we're not supposed to execute a shell, don't. */ if (noExec) { /* * We only want to work our way up the graph if we aren't here * because the commands for the job were no good. */ if (cmdsOK && !aborting) { gn->built_status = MADE; Make_Update(gn); } return NULL; } else { Job *job; /* new job descriptor */ job = emalloc(sizeof(Job)); if (job == NULL) Punt("JobStart out of memory"); job->node = gn; /* * Set the initial value of the flags for this job based on the * global ones and the node's attributes... Any flags supplied * by the caller are also added to the field. */ job->flags = flags; if (gn->type & OP_CHEAP) return job; if ((gn->type & OP_EXPENSIVE) || expensive_commands(&gn->expanded)) job->flags |= JOB_IS_EXPENSIVE; return job; } }
static bool try_to_make_node(GNode *gn) { if (DEBUG(MAKE)) printf("Examining %s...", gn->name); if (gn->unmade != 0) { if (DEBUG(MAKE)) printf(" Requeuing (%d)\n", gn->unmade); add_targets_to_make(&gn->children); Array_Push(&toBeMade, gn); return false; } if (has_been_built(gn)) { if (DEBUG(MAKE)) printf(" already made\n"); return false; } if (has_unmade_predecessor(gn)) { if (DEBUG(MAKE)) printf(" Dropping for now\n"); return false; } /* SIB: this is where there should be a siblings loop */ Suff_FindDeps(gn); if (gn->unmade != 0) { if (DEBUG(MAKE)) printf(" Requeuing (after deps: %d)\n", gn->unmade); add_targets_to_make(&gn->children); return false; } if (Make_OODate(gn)) { /* SIB: if a sibling is getting built, I don't build it right now */ if (DEBUG(MAKE)) printf("out-of-date\n"); if (queryFlag) return true; /* SIB: this is where commands should get prepared */ Make_DoAllVar(gn); /* SIB: this is where I should make the gn as `being built */ gn->build_lock = true; Job_Make(gn); } else { if (DEBUG(MAKE)) printf("up-to-date\n"); gn->built_status = UPTODATE; if (gn->type & OP_JOIN) { /* * Even for an up-to-date .JOIN node, we need it * to have its context variables so references * to it get the correct value for .TARGET when * building up the context variables of its * parent(s)... */ Make_DoAllVar(gn); } Make_Update(gn); } return false; }
static void process_job_status(Job *job, int status) { int reason, code; bool done; debug_printf("Process %ld (%s) exited with status %d.\n", (long)job->pid, job->node->name, status); /* parse status */ if (WIFEXITED(status)) { reason = JOB_EXITED; code = WEXITSTATUS(status); } else if (WIFSIGNALED(status)) { reason = JOB_SIGNALED; code = WTERMSIG(status); } else { /* can't happen, set things to be bad. */ reason = UNKNOWN; code = status; } if ((reason == JOB_EXITED && code != 0 && !(job->node->type & OP_IGNORE)) || reason == JOB_SIGNALED) { /* * If it exited non-zero and either we're doing things our * way or we're not ignoring errors, the job is finished. * Similarly, if the shell died because of a signal * the job is also finished. In these * cases, finish out the job's output before printing the exit * status... */ close_job_pipes(job); done = true; } else if (reason == JOB_EXITED) { /* * Deal with ignored errors. We need to print a message telling * of the ignored error as well as setting status.w_status to 0 * so the next command gets run. To do this, we set done to be * true and the job exited non-zero. */ done = code != 0; close_job_pipes(job); } else { /* * No need to close things down or anything. */ done = false; } if (done || DEBUG(JOB)) { if (reason == JOB_EXITED) { debug_printf("Process %ld (%s) exited.\n", (long)job->pid, job->node->name); if (code != 0) { banner(job, stdout); (void)fprintf(stdout, "*** Error code %d %s\n", code, (job->node->type & OP_IGNORE) ? "(ignored)" : ""); if (job->node->type & OP_IGNORE) { reason = JOB_EXITED; code = 0; } } else if (DEBUG(JOB)) { (void)fprintf(stdout, "*** %ld (%s) Completed successfully\n", (long)job->pid, job->node->name); } } else { banner(job, stdout); (void)fprintf(stdout, "*** Signal %d\n", code); } (void)fflush(stdout); } done = true; if (done && aborting != ABORT_ERROR && aborting != ABORT_INTERRUPT && reason == JOB_EXITED && code == 0) { /* As long as we aren't aborting and the job didn't return a * non-zero status that we shouldn't ignore, we call * Make_Update to update the parents. */ job->node->built_status = MADE; Make_Update(job->node); } else if (!(reason == JOB_EXITED && code == 0)) { register_error(reason, code, job); } free(job); if (errors && !keepgoing && aborting != ABORT_INTERRUPT) aborting = ABORT_ERROR; if (aborting == ABORT_ERROR && Job_Empty()) Finish(errors); }