compat.c revision 319884
1/*	$NetBSD: compat.c,v 1.106 2016/08/26 23:28:39 dholland Exp $	*/
2
3/*
4 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35/*
36 * Copyright (c) 1988, 1989 by Adam de Boor
37 * Copyright (c) 1989 by Berkeley Softworks
38 * All rights reserved.
39 *
40 * This code is derived from software contributed to Berkeley by
41 * Adam de Boor.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 *    notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 *    notice, this list of conditions and the following disclaimer in the
50 *    documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 *    must display the following acknowledgement:
53 *	This product includes software developed by the University of
54 *	California, Berkeley and its contributors.
55 * 4. Neither the name of the University nor the names of its contributors
56 *    may be used to endorse or promote products derived from this software
57 *    without specific prior written permission.
58 *
59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 * SUCH DAMAGE.
70 */
71
72#ifndef MAKE_NATIVE
73static char rcsid[] = "$NetBSD: compat.c,v 1.106 2016/08/26 23:28:39 dholland Exp $";
74#else
75#include <sys/cdefs.h>
76#ifndef lint
77#if 0
78static char sccsid[] = "@(#)compat.c	8.2 (Berkeley) 3/19/94";
79#else
80__RCSID("$NetBSD: compat.c,v 1.106 2016/08/26 23:28:39 dholland Exp $");
81#endif
82#endif /* not lint */
83#endif
84
85/*-
86 * compat.c --
87 *	The routines in this file implement the full-compatibility
88 *	mode of PMake. Most of the special functionality of PMake
89 *	is available in this mode. Things not supported:
90 *	    - different shells.
91 *	    - friendly variable substitution.
92 *
93 * Interface:
94 *	Compat_Run	    Initialize things for this module and recreate
95 *	    	  	    thems as need creatin'
96 */
97
98#ifdef HAVE_CONFIG_H
99# include   "config.h"
100#endif
101#include    <sys/types.h>
102#include    <sys/stat.h>
103#include    "wait.h"
104
105#include    <ctype.h>
106#include    <errno.h>
107#include    <signal.h>
108#include    <stdio.h>
109
110#include    "make.h"
111#include    "hash.h"
112#include    "dir.h"
113#include    "job.h"
114#include    "metachar.h"
115#include    "pathnames.h"
116
117
118static GNode	    *curTarg = NULL;
119static GNode	    *ENDNode;
120static void CompatInterrupt(int);
121
122/*
123 * CompatDeleteTarget -- delete a failed, interrupted, or otherwise
124 * duffed target if not inhibited by .PRECIOUS.
125 */
126static void
127CompatDeleteTarget(GNode *gn)
128{
129    if ((gn != NULL) && !Targ_Precious (gn)) {
130	char	  *p1;
131	char 	  *file = Var_Value(TARGET, gn, &p1);
132
133	if (!noExecute && eunlink(file) != -1) {
134	    Error("*** %s removed", file);
135	}
136
137	free(p1);
138    }
139}
140
141/*-
142 *-----------------------------------------------------------------------
143 * CompatInterrupt --
144 *	Interrupt the creation of the current target and remove it if
145 *	it ain't precious.
146 *
147 * Results:
148 *	None.
149 *
150 * Side Effects:
151 *	The target is removed and the process exits. If .INTERRUPT exists,
152 *	its commands are run first WITH INTERRUPTS IGNORED..
153 *
154 * XXX: is .PRECIOUS supposed to inhibit .INTERRUPT? I doubt it, but I've
155 * left the logic alone for now. - dholland 20160826
156 *
157 *-----------------------------------------------------------------------
158 */
159static void
160CompatInterrupt(int signo)
161{
162    GNode   *gn;
163
164    CompatDeleteTarget(curTarg);
165
166    if ((curTarg != NULL) && !Targ_Precious (curTarg)) {
167	/*
168	 * Run .INTERRUPT only if hit with interrupt signal
169	 */
170	if (signo == SIGINT) {
171	    gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);
172	    if (gn != NULL) {
173		Compat_Make(gn, gn);
174	    }
175	}
176    }
177    if (signo == SIGQUIT)
178	_exit(signo);
179    bmake_signal(signo, SIG_DFL);
180    kill(myPid, signo);
181}
182
183/*-
184 *-----------------------------------------------------------------------
185 * CompatRunCommand --
186 *	Execute the next command for a target. If the command returns an
187 *	error, the node's made field is set to ERROR and creation stops.
188 *
189 * Input:
190 *	cmdp		Command to execute
191 *	gnp		Node from which the command came
192 *
193 * Results:
194 *	0 if the command succeeded, 1 if an error occurred.
195 *
196 * Side Effects:
197 *	The node's 'made' field may be set to ERROR.
198 *
199 *-----------------------------------------------------------------------
200 */
201int
202CompatRunCommand(void *cmdp, void *gnp)
203{
204    char    	  *cmdStart;	/* Start of expanded command */
205    char 	  *cp, *bp;
206    Boolean 	  silent,   	/* Don't print command */
207	    	  doIt;		/* Execute even if -n */
208    volatile Boolean errCheck; 	/* Check errors */
209    WAIT_T 	  reason;   	/* Reason for child's death */
210    int	    	  status;   	/* Description of child's death */
211    pid_t	  cpid;	    	/* Child actually found */
212    pid_t	  retstat;    	/* Result of wait */
213    LstNode 	  cmdNode;  	/* Node where current command is located */
214    const char  ** volatile av;	/* Argument vector for thing to exec */
215    char	** volatile mav;/* Copy of the argument vector for freeing */
216    int	    	  argc;	    	/* Number of arguments in av or 0 if not
217				 * dynamically allocated */
218    Boolean 	  local;    	/* TRUE if command should be executed
219				 * locally */
220    Boolean 	  useShell;    	/* TRUE if command should be executed
221				 * using a shell */
222    char	  * volatile cmd = (char *)cmdp;
223    GNode	  *gn = (GNode *)gnp;
224
225    silent = gn->type & OP_SILENT;
226    errCheck = !(gn->type & OP_IGNORE);
227    doIt = FALSE;
228
229    cmdNode = Lst_Member(gn->commands, cmd);
230    cmdStart = Var_Subst(NULL, cmd, gn, VARF_WANTRES);
231
232    /*
233     * brk_string will return an argv with a NULL in av[0], thus causing
234     * execvp to choke and die horribly. Besides, how can we execute a null
235     * command? In any case, we warn the user that the command expanded to
236     * nothing (is this the right thing to do?).
237     */
238
239    if (*cmdStart == '\0') {
240	free(cmdStart);
241	return(0);
242    }
243    cmd = cmdStart;
244    Lst_Replace(cmdNode, cmdStart);
245
246    if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) {
247	(void)Lst_AtEnd(ENDNode->commands, cmdStart);
248	return(0);
249    }
250    if (strcmp(cmdStart, "...") == 0) {
251	gn->type |= OP_SAVE_CMDS;
252	return(0);
253    }
254
255    while ((*cmd == '@') || (*cmd == '-') || (*cmd == '+')) {
256	switch (*cmd) {
257	case '@':
258	    silent = DEBUG(LOUD) ? FALSE : TRUE;
259	    break;
260	case '-':
261	    errCheck = FALSE;
262	    break;
263	case '+':
264	    doIt = TRUE;
265	    if (!shellName)		/* we came here from jobs */
266		Shell_Init();
267	    break;
268	}
269	cmd++;
270    }
271
272    while (isspace((unsigned char)*cmd))
273	cmd++;
274
275    /*
276     * If we did not end up with a command, just skip it.
277     */
278    if (!*cmd)
279	return (0);
280
281#if !defined(MAKE_NATIVE)
282    /*
283     * In a non-native build, the host environment might be weird enough
284     * that it's necessary to go through a shell to get the correct
285     * behaviour.  Or perhaps the shell has been replaced with something
286     * that does extra logging, and that should not be bypassed.
287     */
288    useShell = TRUE;
289#else
290    /*
291     * Search for meta characters in the command. If there are no meta
292     * characters, there's no need to execute a shell to execute the
293     * command.
294     *
295     * Additionally variable assignments and empty commands
296     * go to the shell. Therefore treat '=' and ':' like shell
297     * meta characters as documented in make(1).
298     */
299
300    useShell = needshell(cmd, FALSE);
301#endif
302
303    /*
304     * Print the command before echoing if we're not supposed to be quiet for
305     * this one. We also print the command if -n given.
306     */
307    if (!silent || NoExecute(gn)) {
308	printf("%s\n", cmd);
309	fflush(stdout);
310    }
311
312    /*
313     * If we're not supposed to execute any commands, this is as far as
314     * we go...
315     */
316    if (!doIt && NoExecute(gn)) {
317	return (0);
318    }
319    if (DEBUG(JOB))
320	fprintf(debug_file, "Execute: '%s'\n", cmd);
321
322again:
323    if (useShell) {
324	/*
325	 * We need to pass the command off to the shell, typically
326	 * because the command contains a "meta" character.
327	 */
328	static const char *shargv[5];
329	int shargc;
330
331	shargc = 0;
332	shargv[shargc++] = shellPath;
333	/*
334	 * The following work for any of the builtin shell specs.
335	 */
336	if (errCheck && shellErrFlag) {
337	    shargv[shargc++] = shellErrFlag;
338	}
339	if (DEBUG(SHELL))
340		shargv[shargc++] = "-xc";
341	else
342		shargv[shargc++] = "-c";
343	shargv[shargc++] = cmd;
344	shargv[shargc++] = NULL;
345	av = shargv;
346	argc = 0;
347	bp = NULL;
348	mav = NULL;
349    } else {
350	/*
351	 * No meta-characters, so no need to exec a shell. Break the command
352	 * into words to form an argument vector we can execute.
353	 */
354	mav = brk_string(cmd, &argc, TRUE, &bp);
355	if (mav == NULL) {
356		useShell = 1;
357		goto again;
358	}
359	av = (void *)mav;
360    }
361
362    local = TRUE;
363
364#ifdef USE_META
365    if (useMeta) {
366	meta_compat_start();
367    }
368#endif
369
370    /*
371     * Fork and execute the single command. If the fork fails, we abort.
372     */
373    cpid = vFork();
374    if (cpid < 0) {
375	Fatal("Could not fork");
376    }
377    if (cpid == 0) {
378	Var_ExportVars();
379#ifdef USE_META
380	if (useMeta) {
381	    meta_compat_child();
382	}
383#endif
384	if (local)
385	    (void)execvp(av[0], (char *const *)UNCONST(av));
386	else
387	    (void)execv(av[0], (char *const *)UNCONST(av));
388	execError("exec", av[0]);
389	_exit(1);
390    }
391
392    free(mav);
393    free(bp);
394
395    Lst_Replace(cmdNode, NULL);
396
397#ifdef USE_META
398    if (useMeta) {
399	meta_compat_parent();
400    }
401#endif
402
403    /*
404     * The child is off and running. Now all we can do is wait...
405     */
406    while (1) {
407
408	while ((retstat = wait(&reason)) != cpid) {
409	    if (retstat > 0)
410		JobReapChild(retstat, reason, FALSE); /* not ours? */
411	    if (retstat == -1 && errno != EINTR) {
412		break;
413	    }
414	}
415
416	if (retstat > -1) {
417	    if (WIFSTOPPED(reason)) {
418		status = WSTOPSIG(reason);		/* stopped */
419	    } else if (WIFEXITED(reason)) {
420		status = WEXITSTATUS(reason);		/* exited */
421#if defined(USE_META) && defined(USE_FILEMON_ONCE)
422		if (useMeta) {
423		    meta_cmd_finish(NULL);
424		}
425#endif
426		if (status != 0) {
427		    if (DEBUG(ERROR)) {
428		        fprintf(debug_file, "\n*** Failed target:  %s\n*** Failed command: ",
429			    gn->name);
430		        for (cp = cmd; *cp; ) {
431    			    if (isspace((unsigned char)*cp)) {
432				fprintf(debug_file, " ");
433			        while (isspace((unsigned char)*cp))
434				    cp++;
435			    } else {
436				fprintf(debug_file, "%c", *cp);
437			        cp++;
438			    }
439		        }
440			fprintf(debug_file, "\n");
441		    }
442		    printf("*** Error code %d", status);
443		}
444	    } else {
445		status = WTERMSIG(reason);		/* signaled */
446		printf("*** Signal %d", status);
447	    }
448
449
450	    if (!WIFEXITED(reason) || (status != 0)) {
451		if (errCheck) {
452#ifdef USE_META
453		    if (useMeta) {
454			meta_job_error(NULL, gn, 0, status);
455		    }
456#endif
457		    gn->made = ERROR;
458		    if (keepgoing) {
459			/*
460			 * Abort the current target, but let others
461			 * continue.
462			 */
463			printf(" (continuing)\n");
464		    } else {
465			printf("\n");
466		    }
467		    if (deleteOnError) {
468			    CompatDeleteTarget(gn);
469		    }
470		} else {
471		    /*
472		     * Continue executing commands for this target.
473		     * If we return 0, this will happen...
474		     */
475		    printf(" (ignored)\n");
476		    status = 0;
477		}
478	    }
479	    break;
480	} else {
481	    Fatal("error in wait: %d: %s", retstat, strerror(errno));
482	    /*NOTREACHED*/
483	}
484    }
485    free(cmdStart);
486
487    return (status);
488}
489
490/*-
491 *-----------------------------------------------------------------------
492 * Compat_Make --
493 *	Make a target.
494 *
495 * Input:
496 *	gnp		The node to make
497 *	pgnp		Parent to abort if necessary
498 *
499 * Results:
500 *	0
501 *
502 * Side Effects:
503 *	If an error is detected and not being ignored, the process exits.
504 *
505 *-----------------------------------------------------------------------
506 */
507int
508Compat_Make(void *gnp, void *pgnp)
509{
510    GNode *gn = (GNode *)gnp;
511    GNode *pgn = (GNode *)pgnp;
512
513    if (!shellName)		/* we came here from jobs */
514	Shell_Init();
515    if (gn->made == UNMADE && (gn == pgn || (pgn->type & OP_MADE) == 0)) {
516	/*
517	 * First mark ourselves to be made, then apply whatever transformations
518	 * the suffix module thinks are necessary. Once that's done, we can
519	 * descend and make all our children. If any of them has an error
520	 * but the -k flag was given, our 'make' field will be set FALSE again.
521	 * This is our signal to not attempt to do anything but abort our
522	 * parent as well.
523	 */
524	gn->flags |= REMAKE;
525	gn->made = BEINGMADE;
526	if ((gn->type & OP_MADE) == 0)
527	    Suff_FindDeps(gn);
528	Lst_ForEach(gn->children, Compat_Make, gn);
529	if ((gn->flags & REMAKE) == 0) {
530	    gn->made = ABORTED;
531	    pgn->flags &= ~REMAKE;
532	    goto cohorts;
533	}
534
535	if (Lst_Member(gn->iParents, pgn) != NULL) {
536	    char *p1;
537	    Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0);
538	    free(p1);
539	}
540
541	/*
542	 * All the children were made ok. Now cmgn->mtime contains the
543	 * modification time of the newest child, we need to find out if we
544	 * exist and when we were modified last. The criteria for datedness
545	 * are defined by the Make_OODate function.
546	 */
547	if (DEBUG(MAKE)) {
548	    fprintf(debug_file, "Examining %s...", gn->name);
549	}
550	if (! Make_OODate(gn)) {
551	    gn->made = UPTODATE;
552	    if (DEBUG(MAKE)) {
553		fprintf(debug_file, "up-to-date.\n");
554	    }
555	    goto cohorts;
556	} else if (DEBUG(MAKE)) {
557	    fprintf(debug_file, "out-of-date.\n");
558	}
559
560	/*
561	 * If the user is just seeing if something is out-of-date, exit now
562	 * to tell him/her "yes".
563	 */
564	if (queryFlag) {
565	    exit(1);
566	}
567
568	/*
569	 * We need to be re-made. We also have to make sure we've got a $?
570	 * variable. To be nice, we also define the $> variable using
571	 * Make_DoAllVar().
572	 */
573	Make_DoAllVar(gn);
574
575	/*
576	 * Alter our type to tell if errors should be ignored or things
577	 * should not be printed so CompatRunCommand knows what to do.
578	 */
579	if (Targ_Ignore(gn)) {
580	    gn->type |= OP_IGNORE;
581	}
582	if (Targ_Silent(gn)) {
583	    gn->type |= OP_SILENT;
584	}
585
586	if (Job_CheckCommands(gn, Fatal)) {
587	    /*
588	     * Our commands are ok, but we still have to worry about the -t
589	     * flag...
590	     */
591	    if (!touchFlag || (gn->type & OP_MAKE)) {
592		curTarg = gn;
593#ifdef USE_META
594		if (useMeta && !NoExecute(gn)) {
595		    meta_job_start(NULL, gn);
596		}
597#endif
598		Lst_ForEach(gn->commands, CompatRunCommand, gn);
599		curTarg = NULL;
600	    } else {
601		Job_Touch(gn, gn->type & OP_SILENT);
602	    }
603	} else {
604	    gn->made = ERROR;
605	}
606#ifdef USE_META
607	if (useMeta && !NoExecute(gn)) {
608	    if (meta_job_finish(NULL) != 0)
609		gn->made = ERROR;
610	}
611#endif
612
613	if (gn->made != ERROR) {
614	    /*
615	     * If the node was made successfully, mark it so, update
616	     * its modification time and timestamp all its parents. Note
617	     * that for .ZEROTIME targets, the timestamping isn't done.
618	     * This is to keep its state from affecting that of its parent.
619	     */
620	    gn->made = MADE;
621	    pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0;
622	    if (!(gn->type & OP_EXEC)) {
623		pgn->flags |= CHILDMADE;
624		Make_TimeStamp(pgn, gn);
625	    }
626	} else if (keepgoing) {
627	    pgn->flags &= ~REMAKE;
628	} else {
629	    PrintOnError(gn, "\nStop.");
630	    exit(1);
631	}
632    } else if (gn->made == ERROR) {
633	/*
634	 * Already had an error when making this beastie. Tell the parent
635	 * to abort.
636	 */
637	pgn->flags &= ~REMAKE;
638    } else {
639	if (Lst_Member(gn->iParents, pgn) != NULL) {
640	    char *p1;
641	    Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0);
642	    free(p1);
643	}
644	switch(gn->made) {
645	    case BEINGMADE:
646		Error("Graph cycles through %s", gn->name);
647		gn->made = ERROR;
648		pgn->flags &= ~REMAKE;
649		break;
650	    case MADE:
651		if ((gn->type & OP_EXEC) == 0) {
652		    pgn->flags |= CHILDMADE;
653		    Make_TimeStamp(pgn, gn);
654		}
655		break;
656	    case UPTODATE:
657		if ((gn->type & OP_EXEC) == 0) {
658		    Make_TimeStamp(pgn, gn);
659		}
660		break;
661	    default:
662		break;
663	}
664    }
665
666cohorts:
667    Lst_ForEach(gn->cohorts, Compat_Make, pgnp);
668    return (0);
669}
670
671/*-
672 *-----------------------------------------------------------------------
673 * Compat_Run --
674 *	Initialize this mode and start making.
675 *
676 * Input:
677 *	targs		List of target nodes to re-create
678 *
679 * Results:
680 *	None.
681 *
682 * Side Effects:
683 *	Guess what?
684 *
685 *-----------------------------------------------------------------------
686 */
687void
688Compat_Run(Lst targs)
689{
690    GNode   	  *gn = NULL;/* Current root target */
691    int	    	  errors;   /* Number of targets not remade due to errors */
692
693    if (!shellName)
694	Shell_Init();
695
696    if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN) {
697	bmake_signal(SIGINT, CompatInterrupt);
698    }
699    if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN) {
700	bmake_signal(SIGTERM, CompatInterrupt);
701    }
702    if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN) {
703	bmake_signal(SIGHUP, CompatInterrupt);
704    }
705    if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN) {
706	bmake_signal(SIGQUIT, CompatInterrupt);
707    }
708
709    ENDNode = Targ_FindNode(".END", TARG_CREATE);
710    ENDNode->type = OP_SPECIAL;
711    /*
712     * If the user has defined a .BEGIN target, execute the commands attached
713     * to it.
714     */
715    if (!queryFlag) {
716	gn = Targ_FindNode(".BEGIN", TARG_NOCREATE);
717	if (gn != NULL) {
718	    Compat_Make(gn, gn);
719            if (gn->made == ERROR) {
720                PrintOnError(gn, "\nStop.");
721                exit(1);
722            }
723	}
724    }
725
726    /*
727     * Expand .USE nodes right now, because they can modify the structure
728     * of the tree.
729     */
730    Make_ExpandUse(targs);
731
732    /*
733     * For each entry in the list of targets to create, call Compat_Make on
734     * it to create the thing. Compat_Make will leave the 'made' field of gn
735     * in one of several states:
736     *	    UPTODATE	    gn was already up-to-date
737     *	    MADE  	    gn was recreated successfully
738     *	    ERROR 	    An error occurred while gn was being created
739     *	    ABORTED	    gn was not remade because one of its inferiors
740     *	    	  	    could not be made due to errors.
741     */
742    errors = 0;
743    while (!Lst_IsEmpty (targs)) {
744	gn = (GNode *)Lst_DeQueue(targs);
745	Compat_Make(gn, gn);
746
747	if (gn->made == UPTODATE) {
748	    printf("`%s' is up to date.\n", gn->name);
749	} else if (gn->made == ABORTED) {
750	    printf("`%s' not remade because of errors.\n", gn->name);
751	    errors += 1;
752	}
753    }
754
755    /*
756     * If the user has defined a .END target, run its commands.
757     */
758    if (errors == 0) {
759	Compat_Make(ENDNode, ENDNode);
760	if (gn->made == ERROR) {
761	    PrintOnError(gn, "\nStop.");
762	    exit(1);
763	}
764    }
765}
766