Merge from vendor branch NTPD:
[dragonfly.git] / usr.bin / make / targ.c
1 /*
2  * Copyright (c) 1988, 1989, 1990, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1989 by Berkeley Softworks
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. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  * @(#)targ.c   8.2 (Berkeley) 3/19/94
39  * $FreeBSD: src/usr.bin/make/targ.c,v 1.10 1999/09/11 13:08:02 hoek Exp $
40  * $DragonFly: src/usr.bin/make/targ.c,v 1.12 2004/11/24 07:19:14 dillon Exp $
41  */
42
43 /*-
44  * targ.c --
45  *      Functions for maintaining the Lst allTargets. Target nodes are
46  * kept in two structures: a Lst, maintained by the list library, and a
47  * hash table, maintained by the hash library.
48  *
49  * Interface:
50  *      Targ_Init               Initialization procedure.
51  *
52  *      Targ_End                Cleanup the module
53  *
54  *      Targ_NewGN              Create a new GNode for the passed target
55  *                              (string). The node is *not* placed in the
56  *                              hash table, though all its fields are
57  *                              initialized.
58  *
59  *      Targ_FindNode           Find the node for a given target, creating
60  *                              and storing it if it doesn't exist and the
61  *                              flags are right (TARG_CREATE)
62  *
63  *      Targ_FindList           Given a list of names, find nodes for all
64  *                              of them. If a name doesn't exist and the
65  *                              TARG_NOCREATE flag was given, an error message
66  *                              is printed. Else, if a name doesn't exist,
67  *                              its node is created.
68  *
69  *      Targ_Ignore             Return TRUE if errors should be ignored when
70  *                              creating the given target.
71  *
72  *      Targ_Silent             Return TRUE if we should be silent when
73  *                              creating the given target.
74  *
75  *      Targ_Precious           Return TRUE if the target is precious and
76  *                              should not be removed if we are interrupted.
77  *
78  * Debugging:
79  *      Targ_PrintGraph         Print out the entire graphm all variables
80  *                              and statistics for the directory cache. Should
81  *                              print something for suffixes, too, but...
82  */
83
84 #include          <stdio.h>
85 #include          <time.h>
86 #include          "make.h"
87 #include          "hash.h"
88 #include          "dir.h"
89
90 static Lst        allTargets;   /* the list of all targets found so far */
91 static Lst        allGNs;       /* List of all the GNodes */
92 static Hash_Table targets;      /* a hash table of same */
93
94 #define HTSIZE  191             /* initial size of hash table */
95
96 static int TargPrintOnlySrc(void *, void *);
97 static int TargPrintName(void *, void *);
98 static int TargPrintNode(void *, void *);
99 static void TargFreeGN(void *);
100
101 /*-
102  *-----------------------------------------------------------------------
103  * Targ_Init --
104  *      Initialize this module
105  *
106  * Results:
107  *      None
108  *
109  * Side Effects:
110  *      The allTargets list and the targets hash table are initialized
111  *-----------------------------------------------------------------------
112  */
113 void
114 Targ_Init (void)
115 {
116     allTargets = Lst_Init (FALSE);
117     Hash_InitTable (&targets, HTSIZE);
118 }
119
120 /*-
121  *-----------------------------------------------------------------------
122  * Targ_End --
123  *      Finalize this module
124  *
125  * Results:
126  *      None
127  *
128  * Side Effects:
129  *      All lists and gnodes are cleared
130  *-----------------------------------------------------------------------
131  */
132 void
133 Targ_End (void)
134 {
135     Lst_Destroy(allTargets, NOFREE);
136     if (allGNs)
137         Lst_Destroy(allGNs, TargFreeGN);
138     Hash_DeleteTable(&targets);
139 }
140
141 /*-
142  *-----------------------------------------------------------------------
143  * Targ_NewGN  --
144  *      Create and initialize a new graph node
145  *
146  * Results:
147  *      An initialized graph node with the name field filled with a copy
148  *      of the passed name
149  *
150  * Side Effects:
151  *      The gnode is added to the list of all gnodes.
152  *-----------------------------------------------------------------------
153  */
154 GNode *
155 Targ_NewGN (char *name)
156 {
157     GNode *gn;
158
159     gn = (GNode *) emalloc (sizeof (GNode));
160     gn->name = estrdup (name);
161     gn->path = (char *) 0;
162     if (name[0] == '-' && name[1] == 'l') {
163         gn->type = OP_LIB;
164     } else {
165         gn->type = 0;
166     }
167     gn->unmade =        0;
168     gn->make =          FALSE;
169     gn->made =          UNMADE;
170     gn->childMade =     FALSE;
171     gn->order =         0;
172     gn->mtime = gn->cmtime = 0;
173     gn->iParents =      Lst_Init (FALSE);
174     gn->cohorts =       Lst_Init (FALSE);
175     gn->parents =       Lst_Init (FALSE);
176     gn->children =      Lst_Init (FALSE);
177     gn->successors =    Lst_Init (FALSE);
178     gn->preds =         Lst_Init (FALSE);
179     gn->context =       Lst_Init (FALSE);
180     gn->commands =      Lst_Init (FALSE);
181     gn->suffix =        NULL;
182
183     if (allGNs == NULL)
184         allGNs = Lst_Init(FALSE);
185     Lst_AtEnd(allGNs, (void *) gn);
186
187     return (gn);
188 }
189
190 /*-
191  *-----------------------------------------------------------------------
192  * TargFreeGN  --
193  *      Destroy a GNode
194  *
195  * Results:
196  *      None.
197  *
198  * Side Effects:
199  *      None.
200  *-----------------------------------------------------------------------
201  */
202 static void
203 TargFreeGN (void *gnp)
204 {
205     GNode *gn = (GNode *) gnp;
206
207
208     free(gn->name);
209     free(gn->path);
210
211     Lst_Destroy(gn->iParents, NOFREE);
212     Lst_Destroy(gn->cohorts, NOFREE);
213     Lst_Destroy(gn->parents, NOFREE);
214     Lst_Destroy(gn->children, NOFREE);
215     Lst_Destroy(gn->successors, NOFREE);
216     Lst_Destroy(gn->preds, NOFREE);
217     Lst_Destroy(gn->context, NOFREE);
218     Lst_Destroy(gn->commands, NOFREE);
219     free(gn);
220 }
221
222
223 /*-
224  *-----------------------------------------------------------------------
225  * Targ_FindNode  --
226  *      Find a node in the list using the given name for matching
227  *
228  * Results:
229  *      The node in the list if it was. If it wasn't, return NULL of
230  *      flags was TARG_NOCREATE or the newly created and initialized node
231  *      if it was TARG_CREATE
232  *
233  * Side Effects:
234  *      Sometimes a node is created and added to the list
235  *-----------------------------------------------------------------------
236  */
237 GNode *
238 Targ_FindNode (char *name, int flags)
239 {
240     GNode         *gn;        /* node in that element */
241     Hash_Entry    *he;        /* New or used hash entry for node */
242     Boolean       isNew;      /* Set TRUE if Hash_CreateEntry had to create */
243                               /* an entry for the node */
244
245
246     if (flags & TARG_CREATE) {
247         he = Hash_CreateEntry (&targets, name, &isNew);
248         if (isNew) {
249             gn = Targ_NewGN (name);
250             Hash_SetValue (he, gn);
251             (void) Lst_AtEnd (allTargets, (void *)gn);
252         }
253     } else {
254         he = Hash_FindEntry (&targets, name);
255     }
256
257     if (he == (Hash_Entry *) NULL) {
258         return (NULL);
259     } else {
260         return ((GNode *) Hash_GetValue (he));
261     }
262 }
263
264 /*-
265  *-----------------------------------------------------------------------
266  * Targ_FindList --
267  *      Make a complete list of GNodes from the given list of names
268  *
269  * Results:
270  *      A complete list of graph nodes corresponding to all instances of all
271  *      the names in names.
272  *
273  * Side Effects:
274  *      If flags is TARG_CREATE, nodes will be created for all names in
275  *      names which do not yet have graph nodes. If flags is TARG_NOCREATE,
276  *      an error message will be printed for each name which can't be found.
277  * -----------------------------------------------------------------------
278  */
279 Lst
280 Targ_FindList (Lst names, int flags)
281 {
282     Lst            nodes;       /* result list */
283     LstNode        ln;          /* name list element */
284     GNode          *gn;         /* node in tLn */
285     char           *name;
286
287     nodes = Lst_Init (FALSE);
288
289     if (Lst_Open (names) == FAILURE) {
290         return (nodes);
291     }
292     while ((ln = Lst_Next (names)) != NULL) {
293         name = (char *)Lst_Datum(ln);
294         gn = Targ_FindNode (name, flags);
295         if (gn != NULL) {
296             /*
297              * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
298              * are added to the list in the order in which they were
299              * encountered in the makefile.
300              */
301             (void) Lst_AtEnd (nodes, (void *)gn);
302             if (gn->type & OP_DOUBLEDEP) {
303                 (void)Lst_Concat (nodes, gn->cohorts, LST_CONCNEW);
304             }
305         } else if (flags == TARG_NOCREATE) {
306             Error ("\"%s\" -- target unknown.", name);
307         }
308     }
309     Lst_Close (names);
310     return (nodes);
311 }
312
313 /*-
314  *-----------------------------------------------------------------------
315  * Targ_Ignore  --
316  *      Return true if should ignore errors when creating gn
317  *
318  * Results:
319  *      TRUE if should ignore errors
320  *
321  * Side Effects:
322  *      None
323  *-----------------------------------------------------------------------
324  */
325 Boolean
326 Targ_Ignore (GNode *gn)
327 {
328     if (ignoreErrors || gn->type & OP_IGNORE) {
329         return (TRUE);
330     } else {
331         return (FALSE);
332     }
333 }
334
335 /*-
336  *-----------------------------------------------------------------------
337  * Targ_Silent  --
338  *      Return true if be silent when creating gn
339  *
340  * Results:
341  *      TRUE if should be silent
342  *
343  * Side Effects:
344  *      None
345  *-----------------------------------------------------------------------
346  */
347 Boolean
348 Targ_Silent (GNode *gn)
349 {
350     if (beSilent || gn->type & OP_SILENT) {
351         return (TRUE);
352     } else {
353         return (FALSE);
354     }
355 }
356
357 /*-
358  *-----------------------------------------------------------------------
359  * Targ_Precious --
360  *      See if the given target is precious
361  *
362  * Results:
363  *      TRUE if it is precious. FALSE otherwise
364  *
365  * Side Effects:
366  *      None
367  *-----------------------------------------------------------------------
368  */
369 Boolean
370 Targ_Precious (GNode *gn)
371 {
372     if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) {
373         return (TRUE);
374     } else {
375         return (FALSE);
376     }
377 }
378
379 /******************* DEBUG INFO PRINTING ****************/
380
381 static GNode      *mainTarg;    /* the main target, as set by Targ_SetMain */
382 /*-
383  *-----------------------------------------------------------------------
384  * Targ_SetMain --
385  *      Set our idea of the main target we'll be creating. Used for
386  *      debugging output.
387  *
388  * Results:
389  *      None.
390  *
391  * Side Effects:
392  *      "mainTarg" is set to the main target's node.
393  *-----------------------------------------------------------------------
394  */
395 void
396 Targ_SetMain (GNode *gn)
397 {
398     mainTarg = gn;
399 }
400
401 static int
402 TargPrintName (void *gnp, void *ppath)
403 {
404     GNode *gn = (GNode *) gnp;
405     printf ("%s ", gn->name);
406 #ifdef notdef
407     if (ppath) {
408         if (gn->path) {
409             printf ("[%s]  ", gn->path);
410         }
411         if (gn == mainTarg) {
412             printf ("(MAIN NAME)  ");
413         }
414     }
415 #endif /* notdef */
416     return (ppath ? 0 : 0);
417 }
418
419
420 int
421 Targ_PrintCmd (void *cmd, void *dummy __unused)
422 {
423     printf ("\t%s\n", (char *) cmd);
424     return (0);
425 }
426
427 /*-
428  *-----------------------------------------------------------------------
429  * Targ_FmtTime --
430  *      Format a modification time in some reasonable way and return it.
431  *
432  * Results:
433  *      The time reformatted.
434  *
435  * Side Effects:
436  *      The time is placed in a static area, so it is overwritten
437  *      with each call.
438  *
439  *-----------------------------------------------------------------------
440  */
441 char *
442 Targ_FmtTime (time_t modtime)
443 {
444     struct tm           *parts;
445     static char         buf[128];
446
447     parts = localtime(&modtime);
448
449     strftime(buf, sizeof buf, "%H:%M:%S %b %d, %Y", parts);
450     buf[sizeof(buf) - 1] = '\0';
451     return(buf);
452 }
453
454 /*-
455  *-----------------------------------------------------------------------
456  * Targ_PrintType --
457  *      Print out a type field giving only those attributes the user can
458  *      set.
459  *
460  * Results:
461  *
462  * Side Effects:
463  *
464  *-----------------------------------------------------------------------
465  */
466 void
467 Targ_PrintType (int type)
468 {
469     int    tbit;
470
471 #define PRINTBIT(attr)  case CONCAT(OP_,attr): printf("." #attr " "); break
472 #define PRINTDBIT(attr) case CONCAT(OP_,attr): DEBUGF(TARG, ("." #attr " ")); break
473
474     type &= ~OP_OPMASK;
475
476     while (type) {
477         tbit = 1 << (ffs(type) - 1);
478         type &= ~tbit;
479
480         switch(tbit) {
481             PRINTBIT(OPTIONAL);
482             PRINTBIT(USE);
483             PRINTBIT(EXEC);
484             PRINTBIT(IGNORE);
485             PRINTBIT(PRECIOUS);
486             PRINTBIT(SILENT);
487             PRINTBIT(MAKE);
488             PRINTBIT(JOIN);
489             PRINTBIT(INVISIBLE);
490             PRINTBIT(NOTMAIN);
491             PRINTDBIT(LIB);
492             /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
493             case OP_MEMBER: DEBUGF(TARG, (".MEMBER ")); break;
494             PRINTDBIT(ARCHV);
495         }
496     }
497 }
498
499 /*-
500  *-----------------------------------------------------------------------
501  * TargPrintNode --
502  *      print the contents of a node
503  *-----------------------------------------------------------------------
504  */
505 static int
506 TargPrintNode (void *gnp, void *passp)
507 {
508     GNode         *gn = (GNode *) gnp;
509     int           pass = *(int *) passp;
510     if (!OP_NOP(gn->type)) {
511         printf("#\n");
512         if (gn == mainTarg) {
513             printf("# *** MAIN TARGET ***\n");
514         }
515         if (pass == 2) {
516             if (gn->unmade) {
517                 printf("# %d unmade children\n", gn->unmade);
518             } else {
519                 printf("# No unmade children\n");
520             }
521             if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
522                 if (gn->mtime != 0) {
523                     printf("# last modified %s: %s\n",
524                               Targ_FmtTime(gn->mtime),
525                               (gn->made == UNMADE ? "unmade" :
526                                (gn->made == MADE ? "made" :
527                                 (gn->made == UPTODATE ? "up-to-date" :
528                                  "error when made"))));
529                 } else if (gn->made != UNMADE) {
530                     printf("# non-existent (maybe): %s\n",
531                               (gn->made == MADE ? "made" :
532                                (gn->made == UPTODATE ? "up-to-date" :
533                                 (gn->made == ERROR ? "error when made" :
534                                  "aborted"))));
535                 } else {
536                     printf("# unmade\n");
537                 }
538             }
539             if (!Lst_IsEmpty (gn->iParents)) {
540                 printf("# implicit parents: ");
541                 Lst_ForEach (gn->iParents, TargPrintName, (void *)0);
542                 fputc ('\n', stdout);
543             }
544         }
545         if (!Lst_IsEmpty (gn->parents)) {
546             printf("# parents: ");
547             Lst_ForEach (gn->parents, TargPrintName, (void *)0);
548             fputc ('\n', stdout);
549         }
550
551         printf("%-16s", gn->name);
552         switch (gn->type & OP_OPMASK) {
553             case OP_DEPENDS:
554                 printf(": "); break;
555             case OP_FORCE:
556                 printf("! "); break;
557             case OP_DOUBLEDEP:
558                 printf(":: "); break;
559             default:
560                 break;
561         }
562         Targ_PrintType (gn->type);
563         Lst_ForEach (gn->children, TargPrintName, (void *)0);
564         fputc ('\n', stdout);
565         Lst_ForEach (gn->commands, Targ_PrintCmd, (void *)0);
566         printf("\n\n");
567         if (gn->type & OP_DOUBLEDEP) {
568             Lst_ForEach (gn->cohorts, TargPrintNode, (void *)&pass);
569         }
570     }
571     return (0);
572 }
573
574 /*-
575  *-----------------------------------------------------------------------
576  * TargPrintOnlySrc --
577  *      Print only those targets that are just a source.
578  *
579  * Results:
580  *      0.
581  *
582  * Side Effects:
583  *      The name of each file is printed preceded by #\t
584  *
585  *-----------------------------------------------------------------------
586  */
587 static int
588 TargPrintOnlySrc(void *gnp, void *dummy __unused)
589 {
590     GNode         *gn = (GNode *) gnp;
591     if (OP_NOP(gn->type))
592         printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
593
594     return (0);
595 }
596
597 /*-
598  *-----------------------------------------------------------------------
599  * Targ_PrintGraph --
600  *      Print the entire graph.
601  *
602  * Results:
603  *      none
604  *
605  * Side Effects:
606  *      lots o' output
607  *-----------------------------------------------------------------------
608  */
609 void
610 Targ_PrintGraph (int pass)
611 {
612     printf("#*** Input graph:\n");
613     Lst_ForEach (allTargets, TargPrintNode, (void *)&pass);
614     printf("\n\n");
615     printf("#\n#   Files that are only sources:\n");
616     Lst_ForEach (allTargets, TargPrintOnlySrc, (void *) 0);
617     printf("#*** Global Variables:\n");
618     Var_Dump (VAR_GLOBAL);
619     printf("#*** Command-line Variables:\n");
620     Var_Dump (VAR_CMD);
621     printf("\n");
622     Dir_PrintDirectories();
623     printf("\n");
624     Suff_PrintAll();
625 }