Make GCC 3.4 the default compiler.
[dragonfly.git] / usr.bin / make / compat.c
1 /*-
2  * Copyright (c) 1988, 1989, 1990, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1988, 1989 by Adam de Boor
5  * Copyright (c) 1989 by Berkeley Softworks
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Adam de Boor.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *      This product includes software developed by the University of
22  *      California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  * @(#)compat.c 8.2 (Berkeley) 3/19/94
40  * $FreeBSD: src/usr.bin/make/compat.c,v 1.50 2005/02/10 14:39:05 harti Exp $
41  * $DragonFly: src/usr.bin/make/Attic/compat.c,v 1.36 2005/04/16 10:34:26 okumoto Exp $
42  */
43
44 /*-
45  * compat.c --
46  *      The routines in this file implement the full-compatibility
47  *      mode of PMake. Most of the special functionality of PMake
48  *      is available in this mode. Things not supported:
49  *          - different shells.
50  *          - friendly variable substitution.
51  *
52  * Interface:
53  *      Compat_Run          Initialize things for this module and recreate
54  *                          thems as need creatin'
55  */
56
57 #include <sys/types.h>
58 #include <sys/wait.h>
59 #include <ctype.h>
60 #include <errno.h>
61 #include <signal.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <unistd.h>
65
66 #include "buf.h"
67 #include "compat.h"
68 #include "config.h"
69 #include "dir.h"
70 #include "globals.h"
71 #include "GNode.h"
72 #include "job.h"
73 #include "make.h"
74 #include "str.h"
75 #include "suff.h"
76 #include "targ.h"
77 #include "util.h"
78 #include "var.h"
79
80 /*
81  * The following array is used to make a fast determination of which
82  * characters are interpreted specially by the shell.  If a command
83  * contains any of these characters, it is executed by the shell, not
84  * directly by us.
85  */
86 static char         meta[256];
87
88 static GNode        *curTarg = NULL;
89 static GNode        *ENDNode;
90 static sig_atomic_t interrupted;
91
92 static void
93 CompatInit(void)
94 {
95         const char      *cp;    /* Pointer to string of shell meta-characters */
96
97         for (cp = "#=|^(){};&<>*?[]:$`\\\n"; *cp != '\0'; cp++) {
98                 meta[(unsigned char)*cp] = 1;
99         }
100         /*
101          * The null character serves as a sentinel in the string.
102          */
103         meta[0] = 1;
104 }
105
106 /*
107  * Interrupt handler - set flag and defer handling to the main code
108  */
109 static void
110 CompatCatchSig(int signo)
111 {
112
113         interrupted = signo;
114 }
115
116 /*-
117  *-----------------------------------------------------------------------
118  * CompatInterrupt --
119  *      Interrupt the creation of the current target and remove it if
120  *      it ain't precious.
121  *
122  * Results:
123  *      None.
124  *
125  * Side Effects:
126  *      The target is removed and the process exits. If .INTERRUPT exists,
127  *      its commands are run first WITH INTERRUPTS IGNORED..
128  *
129  *-----------------------------------------------------------------------
130  */
131 static void
132 CompatInterrupt(int signo)
133 {
134         GNode           *gn;
135         sigset_t        nmask, omask;
136         LstNode         *ln;
137
138         sigemptyset(&nmask);
139         sigaddset(&nmask, SIGINT);
140         sigaddset(&nmask, SIGTERM);
141         sigaddset(&nmask, SIGHUP);
142         sigaddset(&nmask, SIGQUIT);
143         sigprocmask(SIG_SETMASK, &nmask, &omask);
144
145         /* prevent recursion in evaluation of .INTERRUPT */
146         interrupted = 0;
147
148         if (curTarg != NULL && !Targ_Precious(curTarg)) {
149                 char      *p1;
150                 char      *file = Var_Value(TARGET, curTarg, &p1);
151
152                 if (!noExecute && eunlink(file) != -1) {
153                         printf("*** %s removed\n", file);
154                 }
155                 free(p1);
156         }
157
158         /*
159          * Run .INTERRUPT only if hit with interrupt signal
160          */
161         if (signo == SIGINT) {
162                 gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);
163                 if (gn != NULL) {
164                         LST_FOREACH(ln, &gn->commands) {
165                                 if (Compat_RunCommand(Lst_Datum(ln), gn))
166                                         break;
167                         }
168                 }
169         }
170
171         sigprocmask(SIG_SETMASK, &omask, NULL);
172
173         if (signo == SIGQUIT)
174                 exit(signo);
175         signal(signo, SIG_DFL);
176         kill(getpid(), signo);
177 }
178
179 /*-
180  *-----------------------------------------------------------------------
181  * shellneed --
182  *
183  * Results:
184  *      Returns 1 if a specified line must be executed by the shell,
185  *      and 0 if it can be run via execve.
186  *
187  * Side Effects:
188  *      Uses brk_string so destroys the contents of argv.
189  *
190  *-----------------------------------------------------------------------
191  */
192 static int
193 shellneed(char *cmd)
194 {
195         static const char *sh_builtin[] = {
196                 "alias", "cd", "eval", "exec",
197                 "exit", "read", "set", "ulimit",
198                 "unalias", "umask", "unset", "wait",
199                 ":", NULL
200         };
201         char            **av;
202         const char      **p;
203
204         av = brk_string(cmd, NULL, TRUE);
205         for (p = sh_builtin; *p != 0; p++)
206                 if (strcmp(av[1], *p) == 0)
207                         return (1);
208         return (0);
209 }
210
211 /*-
212  *-----------------------------------------------------------------------
213  * Compat_RunCommand --
214  *      Execute the next command for a target. If the command returns an
215  *      error, the node's made field is set to ERROR and creation stops.
216  *      The node from which the command came is also given.
217  *
218  * Results:
219  *      0 if the command succeeded, 1 if an error occurred.
220  *
221  * Side Effects:
222  *      The node's 'made' field may be set to ERROR.
223  *
224  *-----------------------------------------------------------------------
225  */
226 int
227 Compat_RunCommand(char *cmd, GNode *gn)
228 {
229         char    *cmdStart;      /* Start of expanded command */
230         char    *cp;
231         Boolean silent;         /* Don't print command */
232         Boolean doit;           /* Execute even in -n */
233         Boolean errCheck;       /* Check errors */
234         int     reason;         /* Reason for child's death */
235         int     status;         /* Description of child's death */
236         int     cpid;           /* Child actually found */
237         ReturnStatus rstat;     /* Status of fork */
238         LstNode *cmdNode;       /* Node where current command is located */
239         char    **av;           /* Argument vector for thing to exec */
240         char    *cmd_save;      /* saved cmd */
241
242         /*
243          * Avoid clobbered variable warnings by forcing the compiler
244          * to ``unregister'' variables
245          */
246 #if __GNUC__
247         (void)&av;
248         (void)&errCheck;
249 #endif
250         silent = gn->type & OP_SILENT;
251         errCheck = !(gn->type & OP_IGNORE);
252         doit = FALSE;
253
254         cmdNode = Lst_Member(&gn->commands, cmd);
255         cmdStart = Buf_Peel(Var_Subst(cmd, gn, FALSE));
256
257         /*
258          * brk_string will return an argv with a NULL in av[0], thus causing
259          * execvp to choke and die horribly. Besides, how can we execute a null
260          * command? In any case, we warn the user that the command expanded to
261          * nothing (is this the right thing to do?).
262          */
263         if (*cmdStart == '\0') {
264                 free(cmdStart);
265                 Error("%s expands to empty string", cmd);
266                 return (0);
267         } else {
268                 cmd = cmdStart;
269         }
270         Lst_Replace(cmdNode, cmdStart);
271
272         if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) {
273                 Lst_AtEnd(&ENDNode->commands, cmdStart);
274                 return (0);
275         } else if (strcmp(cmdStart, "...") == 0) {
276                 gn->type |= OP_SAVE_CMDS;
277                 return (0);
278         }
279
280         while (*cmd == '@' || *cmd == '-' || *cmd == '+') {
281                 switch (*cmd) {
282
283                   case '@':
284                         silent = DEBUG(LOUD) ? FALSE : TRUE;
285                         break;
286
287                   case '-':
288                         errCheck = FALSE;
289                         break;
290
291                 case '+':
292                         doit = TRUE;
293                         if (!meta[0])           /* we came here from jobs */
294                                 CompatInit();
295                         break;
296                 }
297                 cmd++;
298         }
299
300         while (isspace((unsigned char)*cmd))
301                 cmd++;
302
303         /*
304          * Search for meta characters in the command. If there are no meta
305          * characters, there's no need to execute a shell to execute the
306          * command.
307          */
308         for (cp = cmd; !meta[(unsigned char)*cp]; cp++)
309                 continue;
310
311         /*
312          * Print the command before echoing if we're not supposed to be quiet
313          * for this one. We also print the command if -n given, but not if '+'.
314          */
315         if (!silent || (noExecute && !doit)) {
316                 printf("%s\n", cmd);
317                 fflush(stdout);
318         }
319
320         /*
321          * If we're not supposed to execute any commands, this is as far as
322          * we go...
323          */
324         if (!doit && noExecute) {
325                 return (0);
326         }
327
328         if (*cp != '\0') {
329                 /*
330                  * If *cp isn't the null character, we hit a "meta" character
331                  * and need to pass the command off to the shell. We give the
332                  * shell the -e flag as well as -c if it's supposed to exit
333                  * when it hits an error.
334                  */
335                 static char     *shargv[4];
336
337                 shargv[0] = shellPath;
338                 shargv[1] = (errCheck ? "-ec" : "-c");
339                 shargv[2] = cmd;
340                 shargv[3] = NULL;
341                 av = shargv;
342
343         } else if (shellneed(cmd)) {
344                 /*
345                  * This command must be passed by the shell for other reasons..
346                  * or.. possibly not at all.
347                  */
348                 static char     *shargv[4];
349
350                 shargv[0] = shellPath;
351                 shargv[1] = (errCheck ? "-ec" : "-c");
352                 shargv[2] = cmd;
353                 shargv[3] = NULL;
354                 av = shargv;
355
356         } else {
357                 /*
358                  * No meta-characters, so no need to exec a shell. Break the
359                  * command into words to form an argument vector we can execute.
360                  * brk_string sticks our name in av[0], so we have to
361                  * skip over it...
362                  */
363                 av = brk_string(cmd, NULL, TRUE);
364                 av += 1;
365         }
366
367         /*
368          * Fork and execute the single command. If the fork fails, we abort.
369          */
370         cpid = vfork();
371         if (cpid < 0) {
372                 Fatal("Could not fork");
373         }
374         if (cpid == 0) {
375                 execvp(av[0], av);
376                 write(STDERR_FILENO, av[0], strlen(av[0]));
377                 write(STDERR_FILENO, ":", 1);
378                 write(STDERR_FILENO, strerror(errno), strlen(strerror(errno)));
379                 write(STDERR_FILENO, "\n", 1);
380                 _exit(1);
381         }
382
383         /*
384          * we need to print out the command associated with this Gnode in
385          * Targ_PrintCmd from Targ_PrintGraph when debugging at level g2,
386          * in main(), Fatal() and DieHorribly(), therefore do not free it
387          * when debugging.
388          */
389         if (!DEBUG(GRAPH2)) {
390                 free(cmdStart);
391                 Lst_Replace(cmdNode, cmd_save);
392         }
393
394         /*
395          * The child is off and running. Now all we can do is wait...
396          */
397         while (1) {
398                 while ((rstat = wait(&reason)) != cpid) {
399                         if (interrupted || (rstat == -1 && errno != EINTR)) {
400                                 break;
401                         }
402                 }
403                 if (interrupted)
404                         CompatInterrupt(interrupted);
405
406                 if (rstat > -1) {
407                         if (WIFSTOPPED(reason)) {
408                                 status = WSTOPSIG(reason);      /* stopped */
409                         } else if (WIFEXITED(reason)) {
410                                 status = WEXITSTATUS(reason);   /* exited */
411                                 if (status != 0) {
412                                         printf("*** Error code %d", status);
413                                 }
414                         } else {
415                                 status = WTERMSIG(reason);      /* signaled */
416                                 printf("*** Signal %d", status);
417                         }
418
419                         if (!WIFEXITED(reason) || status != 0) {
420                                 if (errCheck) {
421                                         gn->made = ERROR;
422                                         if (keepgoing) {
423                                                 /*
424                                                  * Abort the current target,
425                                                  * but let others continue.
426                                                  */
427                                                 printf(" (continuing)\n");
428                                         }
429                                 } else {
430                                         /*
431                                          * Continue executing commands for this
432                                          * target. If we return 0, this will
433                                          * happen...
434                                          */
435                                         printf(" (ignored)\n");
436                                         status = 0;
437                                 }
438                         }
439                         break;
440                 } else {
441                         Fatal("error in wait: %d", rstat);
442                         /*NOTREACHED*/
443                 }
444         }
445
446         return (status);
447 }
448
449 /*-
450  *-----------------------------------------------------------------------
451  * CompatMake --
452  *      Make a target, given the parent, to abort if necessary.
453  *
454  * Side Effects:
455  *      If an error is detected and not being ignored, the process exits.
456  *
457  *-----------------------------------------------------------------------
458  */
459 static int
460 CompatMake(GNode *gn, GNode *pgn)
461 {
462         LstNode *ln;
463
464         if (gn->type & OP_USE) {
465                 Make_HandleUse(gn, pgn);
466
467         } else if (gn->made == UNMADE) {
468                 /*
469                  * First mark ourselves to be made, then apply whatever
470                  * transformations the suffix module thinks are necessary.
471                  * Once that's done, we can descend and make all our children.
472                  * If any of them has an error but the -k flag was given, our
473                  * 'make' field will be set FALSE again. This is our signal to
474                  * not attempt to do anything but abort our parent as well.
475                  */
476                 gn->make = TRUE;
477                 gn->made = BEINGMADE;
478                 Suff_FindDeps(gn);
479                 LST_FOREACH(ln, &gn->children)
480                         CompatMake(Lst_Datum(ln), gn);
481                 if (!gn->make) {
482                         gn->made = ABORTED;
483                         pgn->make = FALSE;
484                         return (0);
485                 }
486
487                 if (Lst_Member(&gn->iParents, pgn) != NULL) {
488                         char *p1;
489                         Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn);
490                         free(p1);
491                 }
492
493                 /*
494                  * All the children were made ok. Now cmtime contains the
495                  * modification time of the newest child, we need to find out
496                  * if we exist and when we were modified last. The criteria for
497                  * datedness are defined by the Make_OODate function.
498                  */
499                 DEBUGF(MAKE, ("Examining %s...", gn->name));
500                 if (!Make_OODate(gn)) {
501                         gn->made = UPTODATE;
502                         DEBUGF(MAKE, ("up-to-date.\n"));
503                         return (0);
504                 } else {
505                         DEBUGF(MAKE, ("out-of-date.\n"));
506                 }
507
508                 /*
509                  * If the user is just seeing if something is out-of-date,
510                  * exit now to tell him/her "yes".
511                  */
512                 if (queryFlag) {
513                         exit(1);
514                 }
515
516                 /*
517                  * We need to be re-made. We also have to make sure we've got
518                  * a $? variable. To be nice, we also define the $> variable
519                  * using Make_DoAllVar().
520                  */
521                 Make_DoAllVar(gn);
522
523                 /*
524                  * Alter our type to tell if errors should be ignored or things
525                  * should not be printed so Compat_RunCommand knows what to do.
526                  */
527                 if (Targ_Ignore(gn)) {
528                         gn->type |= OP_IGNORE;
529                 }
530                 if (Targ_Silent(gn)) {
531                         gn->type |= OP_SILENT;
532                 }
533
534                 if (Job_CheckCommands(gn, Fatal)) {
535                         /*
536                          * Our commands are ok, but we still have to worry
537                          * about the -t flag...
538                          */
539                         if (!touchFlag) {
540                                 curTarg = gn;
541                                 LST_FOREACH(ln, &gn->commands) {
542                                         if (Compat_RunCommand(Lst_Datum(ln),
543                                             gn))
544                                                 break;
545                                 }
546                                 curTarg = NULL;
547                         } else {
548                                 Job_Touch(gn, gn->type & OP_SILENT);
549                         }
550                 } else {
551                         gn->made = ERROR;
552                 }
553
554                 if (gn->made != ERROR) {
555                         /*
556                          * If the node was made successfully, mark it so, update
557                          * its modification time and timestamp all its parents.
558                          * Note that for .ZEROTIME targets, the timestamping
559                          * isn't done. This is to keep its state from affecting
560                          * that of its parent.
561                          */
562                         gn->made = MADE;
563 #ifndef RECHECK
564                         /*
565                          * We can't re-stat the thing, but we can at least take
566                          * care of rules where a target depends on a source that
567                          * actually creates the target, but only if it has
568                          * changed, e.g.
569                          *
570                          * parse.h : parse.o
571                          *
572                          * parse.o : parse.y
573                          *      yacc -d parse.y
574                          *      cc -c y.tab.c
575                          *      mv y.tab.o parse.o
576                          *      cmp -s y.tab.h parse.h || mv y.tab.h parse.h
577                          *
578                          * In this case, if the definitions produced by yacc
579                          * haven't changed from before, parse.h won't have been
580                          * updated and gn->mtime will reflect the current
581                          * modification time for parse.h. This is something of a
582                          * kludge, I admit, but it's a useful one..
583                          *
584                          * XXX: People like to use a rule like
585                          *
586                          * FRC:
587                          *
588                          * To force things that depend on FRC to be made, so we
589                          * have to check for gn->children being empty as well...
590                          */
591                         if (!Lst_IsEmpty(&gn->commands) ||
592                             Lst_IsEmpty(&gn->children)) {
593                                 gn->mtime = now;
594                         }
595 #else
596                         /*
597                          * This is what Make does and it's actually a good
598                          * thing, as it allows rules like
599                          *
600                          *      cmp -s y.tab.h parse.h || cp y.tab.h parse.h
601                          *
602                          * to function as intended. Unfortunately, thanks to
603                          * the stateless nature of NFS (and the speed of this
604                          * program), there are times when the modification time
605                          * of a file created on a remote machine will not be
606                          * modified before the stat() implied by the Dir_MTime
607                          * occurs, thus leading us to believe that the file
608                          * is unchanged, wreaking havoc with files that depend
609                          * on this one.
610                          *
611                          * I have decided it is better to make too much than to
612                          * make too little, so this stuff is commented out
613                          * unless you're sure it's ok.
614                          * -- ardeb 1/12/88
615                          */
616                         if (noExecute || Dir_MTime(gn) == 0) {
617                                 gn->mtime = now;
618                         }
619                         if (gn->cmtime > gn->mtime)
620                                 gn->mtime = gn->cmtime;
621                         DEBUGF(MAKE, ("update time: %s\n",
622                             Targ_FmtTime(gn->mtime)));
623 #endif
624                         if (!(gn->type & OP_EXEC)) {
625                                 pgn->childMade = TRUE;
626                                 Make_TimeStamp(pgn, gn);
627                         }
628
629                 } else if (keepgoing) {
630                         pgn->make = FALSE;
631
632                 } else {
633                         char *p1;
634
635                         printf("\n\nStop in %s.\n",
636                             Var_Value(".CURDIR", gn, &p1));
637                         free(p1);
638                         exit(1);
639                 }
640         } else if (gn->made == ERROR) {
641                 /*
642                  * Already had an error when making this beastie. Tell the
643                  * parent to abort.
644                  */
645                 pgn->make = FALSE;
646         } else {
647                 if (Lst_Member(&gn->iParents, pgn) != NULL) {
648                         char *p1;
649                         Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn);
650                         free(p1);
651                 }
652                 switch(gn->made) {
653                   case BEINGMADE:
654                         Error("Graph cycles through %s\n", gn->name);
655                         gn->made = ERROR;
656                         pgn->make = FALSE;
657                         break;
658                   case MADE:
659                         if ((gn->type & OP_EXEC) == 0) {
660                             pgn->childMade = TRUE;
661                             Make_TimeStamp(pgn, gn);
662                         }
663                         break;
664                   case UPTODATE:
665                         if ((gn->type & OP_EXEC) == 0) {
666                             Make_TimeStamp(pgn, gn);
667                         }
668                         break;
669                   default:
670                         break;
671                 }
672         }
673
674         return (0);
675 }
676
677 /*-
678  *-----------------------------------------------------------------------
679  * Compat_Run --
680  *      Start making again, given a list of target nodes.
681  *
682  * Results:
683  *      None.
684  *
685  * Side Effects:
686  *      Guess what?
687  *
688  *-----------------------------------------------------------------------
689  */
690 void
691 Compat_Run(Lst *targs)
692 {
693         GNode   *gn = NULL;     /* Current root target */
694         int     errors;         /* Number of targets not remade due to errors */
695         LstNode *ln;
696
697         CompatInit();
698         Shell_Init();           /* Set up shell. */
699
700         if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
701                 signal(SIGINT, CompatCatchSig);
702         }
703         if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
704                 signal(SIGTERM, CompatCatchSig);
705         }
706         if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
707                 signal(SIGHUP, CompatCatchSig);
708         }
709         if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) {
710                 signal(SIGQUIT, CompatCatchSig);
711         }
712
713         ENDNode = Targ_FindNode(".END", TARG_CREATE);
714         /*
715          * If the user has defined a .BEGIN target, execute the commands
716          * attached to it.
717         */
718         if (!queryFlag) {
719                 gn = Targ_FindNode(".BEGIN", TARG_NOCREATE);
720                 if (gn != NULL) {
721                         LST_FOREACH(ln, &gn->commands) {
722                                 if (Compat_RunCommand(Lst_Datum(ln), gn))
723                                         break;
724                         }
725                         if (gn->made == ERROR) {
726                                 printf("\n\nStop.\n");
727                                 exit(1);
728                         }
729                 }
730         }
731
732         /*
733          * For each entry in the list of targets to create, call CompatMake on
734          * it to create the thing. CompatMake 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 = Lst_DeQueue(targs);
745                 CompatMake(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",
751                             gn->name);
752                         errors += 1;
753                 }
754         }
755
756         /*
757          * If the user has defined a .END target, run its commands.
758          */
759         if (errors == 0) {
760                 LST_FOREACH(ln, &ENDNode->commands) {
761                         if (Compat_RunCommand(Lst_Datum(ln), gn))
762                                 break;
763                 }
764         }
765 }