- Cleanup white space. style(9)
[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.23 2005/01/09 23:03:28 okumoto 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_NewGN              Create a new GNode for the passed target
53  *                              (string). The node is *not* placed in the
54  *                              hash table, though all its fields are
55  *                              initialized.
56  *
57  *      Targ_FindNode           Find the node for a given target, creating
58  *                              and storing it if it doesn't exist and the
59  *                              flags are right (TARG_CREATE)
60  *
61  *      Targ_FindList           Given a list of names, find nodes for all
62  *                              of them. If a name doesn't exist and the
63  *                              TARG_NOCREATE flag was given, an error message
64  *                              is printed. Else, if a name doesn't exist,
65  *                              its node is created.
66  *
67  *      Targ_Ignore             Return TRUE if errors should be ignored when
68  *                              creating the given target.
69  *
70  *      Targ_Silent             Return TRUE if we should be silent when
71  *                              creating the given target.
72  *
73  *      Targ_Precious           Return TRUE if the target is precious and
74  *                              should not be removed if we are interrupted.
75  *
76  * Debugging:
77  *      Targ_PrintGraph         Print out the entire graphm all variables
78  *                              and statistics for the directory cache. Should
79  *                              print something for suffixes, too, but...
80  */
81
82 #include <string.h>
83
84 #include "dir.h"
85 #include "globals.h"
86 #include "GNode.h"
87 #include "hash.h"
88 #include "make.h"
89 #include "suff.h"
90 #include "targ.h"
91 #include "util.h"
92 #include "var.h"
93
94 /* the list of all targets found so far */
95 static Lst allTargets = Lst_Initializer(allTargets);
96
97 static Hash_Table targets;      /* a hash table of same */
98
99 #define HTSIZE  191             /* initial size of hash table */
100
101 static int TargPrintOnlySrc(void *, void *);
102 static int TargPrintName(void *, void *);
103 static int TargPrintNode(void *, void *);
104
105 /*-
106  *-----------------------------------------------------------------------
107  * Targ_Init --
108  *      Initialize this module
109  *
110  * Results:
111  *      None
112  *
113  * Side Effects:
114  *      The allTargets list and the targets hash table are initialized
115  *-----------------------------------------------------------------------
116  */
117 void
118 Targ_Init(void)
119 {
120
121     Hash_InitTable(&targets, HTSIZE);
122 }
123
124 /*-
125  *-----------------------------------------------------------------------
126  * Targ_NewGN  --
127  *      Create and initialize a new graph node
128  *
129  * Results:
130  *      An initialized graph node with the name field filled with a copy
131  *      of the passed name
132  *
133  * Side Effects:
134  *      The gnode is added to the list of all gnodes.
135  *-----------------------------------------------------------------------
136  */
137 GNode *
138 Targ_NewGN(const char *name)
139 {
140     GNode *gn;
141
142     gn = emalloc(sizeof(GNode));
143     gn->name = estrdup(name);
144     gn->path = NULL;
145     if (name[0] == '-' && name[1] == 'l') {
146         gn->type = OP_LIB;
147     } else {
148         gn->type = 0;
149     }
150     gn->unmade = 0;
151     gn->make = FALSE;
152     gn->made = UNMADE;
153     gn->childMade = FALSE;
154     gn->order = 0;
155     gn->mtime = gn->cmtime = 0;
156     Lst_Init(&gn->iParents);
157     Lst_Init(&gn->cohorts);
158     Lst_Init(&gn->parents);
159     Lst_Init(&gn->children);
160     Lst_Init(&gn->successors);
161     Lst_Init(&gn->preds);
162     Lst_Init(&gn->context);
163     Lst_Init(&gn->commands);
164     gn->suffix = NULL;
165
166     return (gn);
167 }
168
169 /*-
170  *-----------------------------------------------------------------------
171  * Targ_FindNode  --
172  *      Find a node in the list using the given name for matching
173  *
174  * Results:
175  *      The node in the list if it was. If it wasn't, return NULL of
176  *      flags was TARG_NOCREATE or the newly created and initialized node
177  *      if it was TARG_CREATE
178  *
179  * Side Effects:
180  *      Sometimes a node is created and added to the list
181  *-----------------------------------------------------------------------
182  */
183 GNode *
184 Targ_FindNode(const char *name, int flags)
185 {
186     GNode         *gn;        /* node in that element */
187     Hash_Entry    *he;        /* New or used hash entry for node */
188     Boolean       isNew;      /* Set TRUE if Hash_CreateEntry had to create */
189                               /* an entry for the node */
190
191     if (flags & TARG_CREATE) {
192         he = Hash_CreateEntry(&targets, name, &isNew);
193         if (isNew) {
194             gn = Targ_NewGN(name);
195             Hash_SetValue(he, gn);
196             Lst_AtEnd(&allTargets, gn);
197         }
198     } else {
199         he = Hash_FindEntry(&targets, name);
200     }
201
202     if (he == NULL) {
203         return (NULL);
204     } else {
205         return (Hash_GetValue(he));
206     }
207 }
208
209 /*-
210  *-----------------------------------------------------------------------
211  * Targ_FindList --
212  *      Make a complete list of GNodes from the given list of names
213  *
214  * Results:
215  *      A complete list of graph nodes corresponding to all instances of all
216  *      the names in names.
217  *
218  * Side Effects:
219  *      If flags is TARG_CREATE, nodes will be created for all names in
220  *      names which do not yet have graph nodes. If flags is TARG_NOCREATE,
221  *      an error message will be printed for each name which can't be found.
222  * -----------------------------------------------------------------------
223  */
224 void
225 Targ_FindList(Lst *nodes, Lst *names, int flags)
226 {
227     LstNode        *ln;         /* name list element */
228     GNode          *gn;         /* node in tLn */
229     char           *name;
230
231     for (ln = Lst_First(names); ln != NULL; ln = Lst_Succ(ln)) {
232         name = Lst_Datum(ln);
233         gn = Targ_FindNode(name, flags);
234         if (gn != NULL) {
235             /*
236              * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
237              * are added to the list in the order in which they were
238              * encountered in the makefile.
239              */
240             Lst_AtEnd(nodes, gn);
241             if (gn->type & OP_DOUBLEDEP) {
242                 Lst_Concat(nodes, &gn->cohorts, LST_CONCNEW);
243             }
244         } else if (flags == TARG_NOCREATE) {
245             Error("\"%s\" -- target unknown.", name);
246         }
247     }
248 }
249
250 /*-
251  *-----------------------------------------------------------------------
252  * Targ_Ignore  --
253  *      Return true if should ignore errors when creating gn
254  *
255  * Results:
256  *      TRUE if should ignore errors
257  *
258  * Side Effects:
259  *      None
260  *-----------------------------------------------------------------------
261  */
262 Boolean
263 Targ_Ignore(GNode *gn)
264 {
265
266     if (ignoreErrors || (gn->type & OP_IGNORE)) {
267         return (TRUE);
268     } else {
269         return (FALSE);
270     }
271 }
272
273 /*-
274  *-----------------------------------------------------------------------
275  * Targ_Silent  --
276  *      Return true if be silent when creating gn
277  *
278  * Results:
279  *      TRUE if should be silent
280  *
281  * Side Effects:
282  *      None
283  *-----------------------------------------------------------------------
284  */
285 Boolean
286 Targ_Silent(GNode *gn)
287 {
288
289     if (beSilent || (gn->type & OP_SILENT)) {
290         return (TRUE);
291     } else {
292         return (FALSE);
293     }
294 }
295
296 /*-
297  *-----------------------------------------------------------------------
298  * Targ_Precious --
299  *      See if the given target is precious
300  *
301  * Results:
302  *      TRUE if it is precious. FALSE otherwise
303  *
304  * Side Effects:
305  *      None
306  *-----------------------------------------------------------------------
307  */
308 Boolean
309 Targ_Precious(GNode *gn)
310 {
311
312     if (allPrecious || (gn->type & (OP_PRECIOUS | OP_DOUBLEDEP))) {
313         return (TRUE);
314     } else {
315         return (FALSE);
316     }
317 }
318
319 /******************* DEBUG INFO PRINTING ****************/
320
321 static GNode      *mainTarg;    /* the main target, as set by Targ_SetMain */
322
323 /*-
324  *-----------------------------------------------------------------------
325  * Targ_SetMain --
326  *      Set our idea of the main target we'll be creating. Used for
327  *      debugging output.
328  *
329  * Results:
330  *      None.
331  *
332  * Side Effects:
333  *      "mainTarg" is set to the main target's node.
334  *-----------------------------------------------------------------------
335  */
336 void
337 Targ_SetMain(GNode *gn)
338 {
339
340     mainTarg = gn;
341 }
342
343 static int
344 TargPrintName(void *gnp, void *ppath)
345 {
346     GNode *gn = (GNode *) gnp;
347
348     printf("%s ", gn->name);
349 #ifdef notdef
350     if (ppath) {
351         if (gn->path) {
352             printf("[%s]  ", gn->path);
353         }
354         if (gn == mainTarg) {
355             printf("(MAIN NAME)  ");
356         }
357     }
358 #endif /* notdef */
359     return (ppath ? 0 : 0);
360 }
361
362
363 int
364 Targ_PrintCmd(void *cmd, void *dummy __unused)
365 {
366
367     printf("\t%s\n", (char *)cmd);
368     return (0);
369 }
370
371 /*-
372  *-----------------------------------------------------------------------
373  * Targ_FmtTime --
374  *      Format a modification time in some reasonable way and return it.
375  *
376  * Results:
377  *      The time reformatted.
378  *
379  * Side Effects:
380  *      The time is placed in a static area, so it is overwritten
381  *      with each call.
382  *
383  *-----------------------------------------------------------------------
384  */
385 char *
386 Targ_FmtTime(time_t modtime)
387 {
388     struct tm           *parts;
389     static char         buf[128];
390
391     parts = localtime(&modtime);
392
393     strftime(buf, sizeof(buf), "%H:%M:%S %b %d, %Y", parts);
394     buf[sizeof(buf) - 1] = '\0';
395     return (buf);
396 }
397
398 /*-
399  *-----------------------------------------------------------------------
400  * Targ_PrintType --
401  *      Print out a type field giving only those attributes the user can
402  *      set.
403  *
404  * Results:
405  *
406  * Side Effects:
407  *
408  *-----------------------------------------------------------------------
409  */
410 void
411 Targ_PrintType(int type)
412 {
413     int    tbit;
414
415 #define PRINTBIT(attr)  case CONCAT(OP_,attr): printf("." #attr " "); break
416 #define PRINTDBIT(attr) case CONCAT(OP_,attr): DEBUGF(TARG, ("." #attr " ")); break
417
418     type &= ~OP_OPMASK;
419
420     while (type) {
421         tbit = 1 << (ffs(type) - 1);
422         type &= ~tbit;
423
424         switch(tbit) {
425             PRINTBIT(OPTIONAL);
426             PRINTBIT(USE);
427             PRINTBIT(EXEC);
428             PRINTBIT(IGNORE);
429             PRINTBIT(PRECIOUS);
430             PRINTBIT(SILENT);
431             PRINTBIT(MAKE);
432             PRINTBIT(JOIN);
433             PRINTBIT(INVISIBLE);
434             PRINTBIT(NOTMAIN);
435             PRINTDBIT(LIB);
436             /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
437             case OP_MEMBER: DEBUGF(TARG, (".MEMBER ")); break;
438             PRINTDBIT(ARCHV);
439         }
440     }
441 }
442
443 /*-
444  *-----------------------------------------------------------------------
445  * TargPrintNode --
446  *      print the contents of a node
447  *-----------------------------------------------------------------------
448  */
449 static int
450 TargPrintNode(void *gnp, void *passp)
451 {
452     GNode         *gn = gnp;
453     int           pass = *(int *)passp;
454
455     if (!OP_NOP(gn->type)) {
456         printf("#\n");
457         if (gn == mainTarg) {
458             printf("# *** MAIN TARGET ***\n");
459         }
460         if (pass == 2) {
461             if (gn->unmade) {
462                 printf("# %d unmade children\n", gn->unmade);
463             } else {
464                 printf("# No unmade children\n");
465             }
466             if (!(gn->type & (OP_JOIN | OP_USE | OP_EXEC))) {
467                 if (gn->mtime != 0) {
468                     printf("# last modified %s: %s\n",
469                               Targ_FmtTime(gn->mtime),
470                               (gn->made == UNMADE ? "unmade" :
471                                (gn->made == MADE ? "made" :
472                                 (gn->made == UPTODATE ? "up-to-date" :
473                                  "error when made"))));
474                 } else if (gn->made != UNMADE) {
475                     printf("# non-existent (maybe): %s\n",
476                               (gn->made == MADE ? "made" :
477                                (gn->made == UPTODATE ? "up-to-date" :
478                                 (gn->made == ERROR ? "error when made" :
479                                  "aborted"))));
480                 } else {
481                     printf("# unmade\n");
482                 }
483             }
484             if (!Lst_IsEmpty(&gn->iParents)) {
485                 printf("# implicit parents: ");
486                 Lst_ForEach(&gn->iParents, TargPrintName, (void *)NULL);
487                 fputc('\n', stdout);
488             }
489         }
490         if (!Lst_IsEmpty(&gn->parents)) {
491             printf("# parents: ");
492             Lst_ForEach(&gn->parents, TargPrintName, (void *)NULL);
493             fputc('\n', stdout);
494         }
495
496         printf("%-16s", gn->name);
497         switch (gn->type & OP_OPMASK) {
498             case OP_DEPENDS:
499                 printf(": "); break;
500             case OP_FORCE:
501                 printf("! "); break;
502             case OP_DOUBLEDEP:
503                 printf(":: "); break;
504             default:
505                 break;
506         }
507         Targ_PrintType(gn->type);
508         Lst_ForEach(&gn->children, TargPrintName, (void *)NULL);
509         fputc('\n', stdout);
510         Lst_ForEach(&gn->commands, Targ_PrintCmd, (void *)NULL);
511         printf("\n\n");
512         if (gn->type & OP_DOUBLEDEP) {
513             Lst_ForEach(&gn->cohorts, TargPrintNode, &pass);
514         }
515     }
516     return (0);
517 }
518
519 /*-
520  *-----------------------------------------------------------------------
521  * TargPrintOnlySrc --
522  *      Print only those targets that are just a source.
523  *
524  * Results:
525  *      0.
526  *
527  * Side Effects:
528  *      The name of each file is printed preceded by #\t
529  *
530  *-----------------------------------------------------------------------
531  */
532 static int
533 TargPrintOnlySrc(void *gnp, void *dummy __unused)
534 {
535     GNode         *gn = gnp;
536
537     if (OP_NOP(gn->type))
538         printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
539
540     return (0);
541 }
542
543 /*-
544  *-----------------------------------------------------------------------
545  * Targ_PrintGraph --
546  *      Print the entire graph.
547  *
548  * Results:
549  *      none
550  *
551  * Side Effects:
552  *      lots o' output
553  *-----------------------------------------------------------------------
554  */
555 void
556 Targ_PrintGraph(int pass)
557 {
558
559     printf("#*** Input graph:\n");
560     Lst_ForEach(&allTargets, TargPrintNode, &pass);
561     printf("\n\n");
562     printf("#\n#   Files that are only sources:\n");
563     Lst_ForEach(&allTargets, TargPrintOnlySrc, (void *)NULL);
564     printf("#*** Global Variables:\n");
565     Var_Dump(VAR_GLOBAL);
566     printf("#*** Command-line Variables:\n");
567     Var_Dump(VAR_CMD);
568     printf("\n");
569     Dir_PrintDirectories();
570     printf("\n");
571     Suff_PrintAll();
572 }