removed some OS/2 remnants
[k8jam.git] / src / make1.c
blob75fcd4fe857f1abb8c4bfea111a45c6125db1234
1 /*
2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6 /*
7 * make1.c - execute command to bring targets up to date
9 * This module contains make1(), the entry point called by make() to
10 * recursively decend the dependency graph executing update actions as
11 * marked by make0().
13 * External routines:
15 * make1() - execute commands to update a TARGET and all its dependents
17 * Internal routines, the recursive/asynchronous command executors:
19 * make1a() - recursively traverse target tree, calling make1b()
20 * make1b() - dependents of target built, now build target with make1c()
21 * make1c() - launch target's next command, call make1b() when done
22 * make1d() - handle command execution completion and call back make1c()
24 * Internal support routines:
26 * make1cmds() - turn ACTIONS into CMDs, grouping, splitting, etc
27 * make1list() - turn a list of targets into a LIST, for $(<) and $(>)
28 * make1settings() - for vars that get bound, build up replacement lists
29 * make1bind() - bind targets that weren't bound in dependency analysis
31 * 04/16/94 (seiwald) - Split from make.c.
32 * 04/21/94 (seiwald) - Handle empty "updated" actions.
33 * 05/04/94 (seiwald) - async multiprocess (-j) support
34 * 06/01/94 (seiwald) - new 'actions existing' does existing sources
35 * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
36 * 01/19/95 (seiwald) - distinguish between CANTFIND/CANTMAKE targets.
37 * 01/22/94 (seiwald) - pass per-target JAMSHELL down to execcmd().
38 * 02/28/95 (seiwald) - Handle empty "existing" actions.
39 * 03/10/95 (seiwald) - Fancy counts.
40 * 02/07/01 (seiwald) - Fix jam -d0 return status.
41 * 01/21/02 (seiwald) - new -q to quit quickly on build failure
42 * 02/28/02 (seiwald) - don't delete 'actions updated' targets on failure
43 * 02/28/02 (seiwald) - merge EXEC_xxx flags in with RULE_xxx
44 * 07/17/02 (seiwald) - TEMPORARY sources for headers now get built
45 * 09/23/02 (seiwald) - "...using temp..." only displayed on -da now.
46 * 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
47 * 11/04/02 (seiwald) - const-ing for string literals
48 * 12/03/02 (seiwald) - fix odd includes support by grafting them onto depends
50 #include <unistd.h>
52 #include "jam.h"
54 #include "lists.h"
55 #include "parse.h"
56 #include "variable.h"
57 #include "rules.h"
59 #include "search.h"
60 #include "newstr.h"
61 #include "make.h"
62 #include "command.h"
63 #include "execcmd.h"
65 //#ifdef OPT_IMPROVED_PROGRESS_EXT
66 #include "progress.h"
67 //#endif
70 static void make1a (TARGET *t, TARGET *parent);
71 static void make1b (TARGET *t);
72 static void make1c (TARGET *t);
73 static void make1d (void *closure, int status);
75 static CMD *make1cmds (ACTIONS *a0);
76 static LIST *make1list (LIST *l, TARGETS *targets, int flags);
77 static SETTINGS *make1settings (LIST *vars);
78 static void make1bind (TARGET *t, int warn);
81 /* Ugly static - it's too hard to carry it through the callbacks. */
82 static struct {
83 int failed;
84 int skipped;
85 int total;
86 int made;
87 } counts[1];
91 * make1() - execute commands to update a TARGET and all its dependents
93 static int intr = 0;
96 int make1 (TARGET *t) {
97 memset((char *)counts, 0, sizeof(*counts));
98 /* recursively make the target and its dependents */
99 make1a(t, (TARGET *)0);
100 /* wait for any outstanding commands to finish running */
101 while (execwait()) ;
102 /* talk about it */
103 if (DEBUG_MAKE && counts->failed) printf("...failed updating %d target%s...\n", counts->failed, multiFormSfx(counts->failed));
104 if (DEBUG_MAKE && counts->skipped) printf("...skipped %d target%s...\n", counts->skipped, multiFormSfx(counts->skipped));
105 if (DEBUG_MAKE && counts->made && !is_make_silent()) printf("...updated %d target%s...\n", counts->made, multiFormSfx(counts->made));
106 return counts->total != counts->made;
111 * make1a() - recursively traverse target tree, calling make1b()
113 static void make1a (TARGET *t, TARGET *parent) {
114 TARGETS *c;
115 /* if the parent is the first to try to build this target */
116 /* or this target is in the make1c() quagmire, arrange for the */
117 /* parent to be notified when this target is built */
118 if (parent) {
119 switch (t->progress) {
120 case T_MAKE_INIT:
121 case T_MAKE_ACTIVE:
122 case T_MAKE_RUNNING:
123 t->parents = targetentry(t->parents, parent);
124 ++parent->asynccnt;
125 break;
128 if (t->progress != T_MAKE_INIT) return;
129 /* asynccnt counts the dependents preventing this target from proceeding to make1b() for actual building */
130 /* we start off with a count of 1 to prevent anything from happening until we can call all dependents */
131 /* this 1 is accounted for when we call make1b() ourselves, below */
132 t->asynccnt = 1;
133 /* recurse on our dependents, manipulating progress to guard against circular dependency */
134 t->progress = T_MAKE_ONSTACK;
135 for (c = t->depends; c && !intr; c = c->next) make1a(c->target, t);
136 t->progress = T_MAKE_ACTIVE;
137 /* now that all dependents have bumped asynccnt, we now allow decrement our reference to asynccnt */
138 make1b(t);
143 * make1b() - dependents of target built, now build target with make1c()
145 static void make1b (TARGET *t) {
146 TARGETS *c;
147 const char *failed = "dependents";
148 /* if any dependents are still outstanding, wait until they call make1b() to signal their completion */
149 if (--t->asynccnt) return;
150 #ifdef JAM_OPT_SEMAPHORE
151 if (t->semaphore && t->semaphore->asynccnt) {
152 /* append 't' to the list of targets waiting on semaphore. */
153 t->semaphore->parents = targetentry(t->semaphore->parents, t);
154 ++t->asynccnt;
155 if (DEBUG_EXECCMD) printf( "SEM: %s is busy, delaying launch of %s\n", t->semaphore->name, t->name );
156 //pop_state(&state_stack);
157 return;
159 #endif
160 /* now ready to build target 't'... if dependents built ok */
161 /* collect status from dependents */
162 for (c = t->depends; c; c = c->next) {
163 if (c->target->status > t->status) {
164 failed = c->target->name;
165 t->status = c->target->status;
168 /* if actions on deps have failed, bail, otherwise, execute all actions to make target */
169 if (t->status == EXEC_CMD_FAIL && t->actions) {
170 ++counts->skipped;
171 printf("...skipped %s for lack of %s...\n", t->name, failed);
173 if (t->status == EXEC_CMD_OK) {
174 switch(t->fate) {
175 case T_FATE_INIT:
176 case T_FATE_MAKING:
177 /* shouldn't happen */
178 case T_FATE_STABLE:
179 case T_FATE_NEWER:
180 break;
181 case T_FATE_CANTFIND:
182 case T_FATE_CANTMAKE:
183 t->status = EXEC_CMD_FAIL;
184 break;
185 case T_FATE_ISTMP:
186 if (DEBUG_MAKEQ) printf("...using %s...\n", t->name);
187 break;
188 case T_FATE_TOUCHED:
189 case T_FATE_MISSING:
190 case T_FATE_NEEDTMP:
191 case T_FATE_OUTDATED:
192 case T_FATE_UPDATE:
193 /* set "on target" vars, build actions, unset vars */
194 /* set "progress" so that make1c() counts this target among the successes/failures. */
195 if (t->actions) {
196 ++counts->total;
197 #ifdef __NEATCC__
198 if (DEBUG_MAKE && !(counts->total % 100)) printf("...on %dth target...\n", counts->total);
199 #else
201 double est_remaining = progress_update(globs.progress, counts->total);
202 if (est_remaining > 0.0) {
203 int minutes = (int)est_remaining/60;
204 int seconds = (int)est_remaining%60;
205 if (minutes > 0 || seconds > 0) {
206 printf("*** completed %.0f%% (", ((double)counts->total*100/globs.updating));
207 if (minutes > 0) printf("%d min ", minutes);
208 if (seconds >= 0) printf("%d sec ", seconds);
209 printf("remaining)...\n");
213 #endif
214 pushsettings(t->settings);
215 t->cmds = (char *)make1cmds(t->actions);
216 popsettings(t->settings);
217 t->progress = T_MAKE_RUNNING;
219 break;
222 /* call make1c() to begin the execution of the chain of commands needed to build target */
223 /* if we're not going to build target (because of dependency failures or because no commands
224 * need to be run) the chain will be empty and make1c() will directly
225 * signal the completion of target */
226 #ifdef JAM_OPT_SEMAPHORE
227 /* if there is a semaphore, indicate that it is in use */
228 if (pState->t->semaphore) {
229 ++pState->t->semaphore->asynccnt;
230 if (DEBUG_EXECCMD) printf( "SEM: %s now used by %s\n", pState->t->semaphore->name, pState->t->name);
232 #endif
233 make1c(t); //pState->curstate = T_STATE_MAKE1C;
238 * make1c() - launch target's next command, call make1b() when done
240 static void make1c (TARGET *t) {
241 CMD *cmd = (CMD *)t->cmds;
242 /* if there are (more) commands to run to build this target
243 * (and we haven't hit an error running earlier comands) we
244 * launch the command with execcmd() */
245 /* if there are no more commands to run, we collect the status
246 * from all the actions then report our completion to all the
247 * parents */
248 if (cmd && t->status == EXEC_CMD_OK) {
249 if (DEBUG_MAKE) {
250 if (DEBUG_MAKEQ || !(cmd->rule->flags&RULE_QUIETLY)) {
251 printf("(%3d%%) ", counts->total*100/globs.updating);
252 printf("%s ", cmd->rule->name);
253 list_print(lol_get(&cmd->args, 0));
254 printf("\n");
257 if (DEBUG_EXEC) printf("%s\n", dstr_cstr(&cmd->buf));
258 if (globs.cmdout) fprintf(globs.cmdout, "%s", dstr_cstr(&cmd->buf));
259 if (globs.noexec) make1d(t, EXEC_CMD_OK);
260 else {
261 fflush(stdout);
262 execcmd(dstr_cstr(&cmd->buf), make1d, t, cmd->shell);
264 } else {
265 TARGETS *c;
266 ACTIONS *actions;
267 /* collect status from actions, and distribute it as well */
268 for (actions = t->actions; actions; actions = actions->next) {
269 if (actions->action->status > t->status) t->status = actions->action->status;
271 for (actions = t->actions; actions; actions = actions->next) {
272 if (t->status > actions->action->status) actions->action->status = t->status;
274 /* tally success/failure for those we tried to update */
275 if (t->progress == T_MAKE_RUNNING) {
276 switch(t->status) {
277 case EXEC_CMD_OK: ++counts->made; break;
278 case EXEC_CMD_FAIL: ++counts->failed; break;
281 /* tell parents dependent has been built */
282 t->progress = T_MAKE_DONE;
283 for (c = t->parents; c; c = c->next) make1b(c->target);
284 #ifdef JAM_OPT_SEMAPHORE
285 /* if there is a semaphore, it is now free */
286 if (t->semaphore) {
287 assert(t->semaphore->asynccnt == 1);
288 --t->semaphore->asynccnt;
289 if (DEBUG_EXECCMD) printf( "SEM: %s is now free\n", t->semaphore->name );
290 /* If anything is waiting, notify the next target */
291 /* there is no point in notifying waiting targets, since they will be notified again */
292 if (t->semaphore->parents) {
293 TARGETS *first = t->semaphore->parents;
294 if (first->next) first->next->tail = first->tail;
295 t->semaphore->parents = first->next;
296 if (DEBUG_EXECCMD) printf( "SEM: placing %s on stack\n", first->target->name );
297 push_state(&temp_stack, first->target, NULL, T_STATE_MAKE1B);
298 BJAM_FREE(first);
301 #endif
307 * make1d() - handle command execution completion and call back make1c()
309 static void make1d (void *closure, int status) {
310 TARGET *t = (TARGET *)closure;
311 CMD *cmd = (CMD *)t->cmds;
312 /* execcmd() has completed */
313 /* all we need to do is fiddle with the status and signal our completion so make1c() can run the next command */
314 /* in interrupts, we bail heavily */
315 if (status == EXEC_CMD_FAIL && (cmd->rule->flags & RULE_IGNORE)) status = EXEC_CMD_OK;
316 /* on interrupt, set intr so _everything_ fails */
317 if (status == EXEC_CMD_INTR) ++intr;
318 if (status == EXEC_CMD_FAIL && DEBUG_MAKE) {
319 /* print command text on failure */
320 if (!DEBUG_EXEC) printf("%s\n", dstr_cstr(&cmd->buf));
321 printf("...failed %s ", cmd->rule->name);
322 list_print(lol_get(&cmd->args, 0));
323 printf("...\n");
324 if (globs.quitquick) ++intr;
326 /* if the command was interrupted or failed and the target is not "precious", remove the targets */
327 /* precious == 'actions updated' -- the target maintains state */
328 if (status != EXEC_CMD_OK && !(cmd->rule->flags & RULE_UPDATED)) {
329 LIST *targets = lol_get(&cmd->args, 0);
330 for (; targets; targets = list_next(targets)) {
331 if (!unlink(targets->string)) printf("...removing %s\n", targets->string);
334 /* free this command and call make1c() to move onto next command */
335 t->status = status;
336 t->cmds = (char *)cmd_next(cmd);
337 cmd_free(cmd);
338 make1c(t);
343 * make1cmds() - turn ACTIONS into CMDs, grouping, splitting, etc
345 * Essentially copies a chain of ACTIONs to a chain of CMDs,
346 * grouping RULE_TOGETHER actions, splitting RULE_PIECEMEAL actions,
347 * and handling RULE_UPDATED actions. The result is a chain of
348 * CMDs which can be expanded by var_string() and executed with
349 * execcmd().
351 static CMD *make1cmds (ACTIONS *a0) {
352 CMD *cmds = 0;
353 LIST *shell = var_get("JAMSHELL"); /* shell is per-target */
354 /* step through actions */
355 /* actions may be shared with other targets or grouped with RULE_TOGETHER, so actions already seen are skipped */
356 for (; a0; a0 = a0->next) {
357 RULE *rule = a0->action->rule;
358 SETTINGS *boundvars;
359 LIST *nt, *ns;
360 ACTIONS *a1;
361 int start, chunk, length, maxline;
362 /* only do rules with commands to execute */
363 /* if this action has already been executed, use saved status */
364 if (!rule->actions || a0->action->running) continue;
365 a0->action->running = 1;
366 /* make LISTS of targets and sources */
367 /* if `execute together` has been specified for this rule, tack
368 * on sources from each instance of this rule for this target */
369 nt = make1list(L0, a0->action->targets, 0);
370 ns = make1list(L0, a0->action->sources, rule->flags);
371 if (rule->flags & RULE_TOGETHER) {
372 for (a1 = a0->next; a1; a1 = a1->next) {
373 if (a1->action->rule == rule && !a1->action->running) {
374 ns = make1list(ns, a1->action->sources, rule->flags);
375 a1->action->running = 1;
379 /* if doing only updated (or existing) sources, but none have
380 * been updated (or exist), skip this action */
381 if (!ns && (rule->flags & (RULE_UPDATED | RULE_EXISTING))) {
382 list_free(nt);
383 continue;
385 /* if we had 'actions xxx bind vars' we bind the vars now */
386 boundvars = make1settings(rule->bindlist);
387 pushsettings(boundvars);
389 * Build command, starting with all source args.
391 * If cmd_new returns 0, it's because the resulting command
392 * length is > MAXLINE. In this case, we'll slowly reduce
393 * the number of source arguments presented until it does
394 * fit. This only applies to actions that allow PIECEMEAL
395 * commands.
397 * While reducing slowly takes a bit of compute time to get
398 * things just right, it's worth it to get as close to MAXLINE
399 * as possible, because launching the commands we're executing
400 * is likely to be much more compute intensive!
402 * Note we loop through at least once, for sourceless actions.
404 * Max line length is the action specific maxline or, if not
405 * given or bigger than MAXLINE, MAXLINE.
407 start = 0;
408 chunk = length = list_length(ns);
409 maxline = rule->flags / RULE_MAXLINE;
410 maxline = maxline && maxline < MAXLINE ? maxline : MAXLINE;
411 do {
412 /* build cmd: cmd_new consumes its lists */
413 CMD *cmd = cmd_new(rule,
414 list_copy(L0, nt),
415 list_sublist(ns, start, chunk),
416 list_copy(L0, shell),
417 maxline);
418 if (cmd) {
419 /* it fit: chain it up */
420 if (!cmds) cmds = cmd; else cmds->tail->next = cmd;
421 cmds->tail = cmd;
422 start += chunk;
423 } else if ((rule->flags & RULE_PIECEMEAL) && chunk > 1) {
424 /* reduce chunk size slowly */
425 chunk = chunk*9/10;
426 } else {
427 /* too long and not splittable */
428 printf("%s actions too long (max %d)!\n", rule->name, maxline);
429 exit(EXITBAD);
431 } while (start < length);
432 /* these were always copied when used */
433 list_free(nt);
434 list_free(ns);
435 /* free the variables whose values were bound by 'actions xxx bind vars' */
436 popsettings(boundvars);
437 freesettings(boundvars);
439 return cmds;
444 * make1list() - turn a list of targets into a LIST, for $(<) and $(>)
446 static LIST *make1list (LIST *l, TARGETS *targets, int flags) {
447 for (; targets; targets = targets->next) {
448 TARGET *t = targets->target;
449 /* sources to 'actions existing' are never in the dependency
450 * graph (if they were, they'd get built and 'existing' would
451 * be superfluous, so throttle warning message about independent
452 * targets */
453 if (t->binding == T_BIND_UNBOUND) make1bind(t, !(flags & RULE_EXISTING));
454 if ((flags & RULE_EXISTING) && t->binding != T_BIND_EXISTS) continue;
455 if ((flags & RULE_UPDATED) && t->fate <= T_FATE_STABLE) continue;
456 /* prohibit duplicates for RULE_TOGETHER */
457 if (flags & RULE_TOGETHER) {
458 LIST *m;
460 for (m = l; m; m = m->next) if (!strcmp(m->string, t->boundname)) break;
461 if (m) continue;
463 /* build new list */
464 l = list_new(l, t->boundname, 1);
466 return l;
471 * make1settings() - for vars that get bound values, build up replacement lists
473 static SETTINGS *make1settings (LIST *vars) {
474 SETTINGS *settings = NULL;
476 for (; vars; vars = list_next(vars)) {
477 LIST *l = var_get(vars->string), *nl = NULL;
479 for (; l; l = list_next(l)) {
480 TARGET *t = bindtarget(l->string);
481 /* make sure the target is bound, warning if it is not in the dependency graph */
482 if (t->binding == T_BIND_UNBOUND) make1bind(t, 1);
483 /* build new list */
484 nl = list_new(nl, t->boundname, 1);
486 /* add to settings chain */
487 settings = addsettings(settings, 0, vars->string, nl);
489 return settings;
494 * make1bind() - bind targets that weren't bound in dependency analysis
496 * Spot the kludge! If a target is not in the dependency tree, it didn't
497 * get bound by make0(), so we have to do it here. Ugly.
499 static void make1bind (TARGET *t, int warn) {
500 if (t->flags & T_FLAG_NOTFILE) return;
501 /* sources to 'actions existing' are never in the dependency
502 * graph (if they were, they'd get built and 'existing' would
503 * be superfluous, so throttle warning message about independent
504 * targets */
505 if (warn) printf("warning: using independent target %s\n", t->name);
506 pushsettings(t->settings);
507 t->boundname = search(t->name, &t->time);
508 t->binding = t->time?T_BIND_EXISTS:T_BIND_MISSING;
509 popsettings(t->settings);