Make needs no circular lists so remove them from the list code.
[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.15 2004/12/16 23:24:09 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_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
117     allTargets = Lst_Init();
118     Hash_InitTable(&targets, HTSIZE);
119 }
120
121 /*-
122  *-----------------------------------------------------------------------
123  * Targ_End --
124  *      Finalize this module
125  *
126  * Results:
127  *      None
128  *
129  * Side Effects:
130  *      All lists and gnodes are cleared
131  *-----------------------------------------------------------------------
132  */
133 void
134 Targ_End(void)
135 {
136
137     Lst_Destroy(allTargets, NOFREE);
138     if (allGNs)
139         Lst_Destroy(allGNs, TargFreeGN);
140     Hash_DeleteTable(&targets);
141 }
142
143 /*-
144  *-----------------------------------------------------------------------
145  * Targ_NewGN  --
146  *      Create and initialize a new graph node
147  *
148  * Results:
149  *      An initialized graph node with the name field filled with a copy
150  *      of the passed name
151  *
152  * Side Effects:
153  *      The gnode is added to the list of all gnodes.
154  *-----------------------------------------------------------------------
155  */
156 GNode *
157 Targ_NewGN(char *name)
158 {
159     GNode *gn;
160
161     gn = emalloc(sizeof(GNode));
162     gn->name = estrdup(name);
163     gn->path = NULL;
164     if (name[0] == '-' && name[1] == 'l') {
165         gn->type = OP_LIB;
166     } else {
167         gn->type = 0;
168     }
169     gn->unmade = 0;
170     gn->make = FALSE;
171     gn->made = UNMADE;
172     gn->childMade = FALSE;
173     gn->order = 0;
174     gn->mtime = gn->cmtime = 0;
175     gn->iParents = Lst_Init();
176     gn->cohorts = Lst_Init();
177     gn->parents = Lst_Init();
178     gn->children = Lst_Init();
179     gn->successors = Lst_Init();
180     gn->preds = Lst_Init();
181     gn->context = Lst_Init();
182     gn->commands = Lst_Init();
183     gn->suffix = NULL;
184
185     if (allGNs == NULL)
186         allGNs = Lst_Init();
187     Lst_AtEnd(allGNs, (void *)gn);
188
189     return (gn);
190 }
191
192 /*-
193  *-----------------------------------------------------------------------
194  * TargFreeGN  --
195  *      Destroy a GNode
196  *
197  * Results:
198  *      None.
199  *
200  * Side Effects:
201  *      None.
202  *-----------------------------------------------------------------------
203  */
204 static void
205 TargFreeGN(void *gnp)
206 {
207     GNode *gn = gnp;
208
209     free(gn->name);
210     free(gn->path);
211
212     Lst_Destroy(gn->iParents, NOFREE);
213     Lst_Destroy(gn->cohorts, NOFREE);
214     Lst_Destroy(gn->parents, NOFREE);
215     Lst_Destroy(gn->children, NOFREE);
216     Lst_Destroy(gn->successors, NOFREE);
217     Lst_Destroy(gn->preds, NOFREE);
218     Lst_Destroy(gn->context, NOFREE);
219     Lst_Destroy(gn->commands, NOFREE);
220     free(gn);
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     if (flags & TARG_CREATE) {
246         he = Hash_CreateEntry(&targets, name, &isNew);
247         if (isNew) {
248             gn = Targ_NewGN(name);
249             Hash_SetValue (he, gn);
250             Lst_AtEnd(allTargets, gn);
251         }
252     } else {
253         he = Hash_FindEntry(&targets, name);
254     }
255
256     if (he == NULL) {
257         return (NULL);
258     } else {
259         return (Hash_GetValue(he));
260     }
261 }
262
263 /*-
264  *-----------------------------------------------------------------------
265  * Targ_FindList --
266  *      Make a complete list of GNodes from the given list of names
267  *
268  * Results:
269  *      A complete list of graph nodes corresponding to all instances of all
270  *      the names in names.
271  *
272  * Side Effects:
273  *      If flags is TARG_CREATE, nodes will be created for all names in
274  *      names which do not yet have graph nodes. If flags is TARG_NOCREATE,
275  *      an error message will be printed for each name which can't be found.
276  * -----------------------------------------------------------------------
277  */
278 Lst
279 Targ_FindList(Lst names, int flags)
280 {
281     Lst            nodes;       /* result list */
282     LstNode        ln;          /* name list element */
283     GNode          *gn;         /* node in tLn */
284     char           *name;
285
286     nodes = Lst_Init();
287
288     if (Lst_Open(names) == FAILURE) {
289         return (nodes);
290     }
291     while ((ln = Lst_Next(names)) != NULL) {
292         name = Lst_Datum(ln);
293         gn = Targ_FindNode(name, flags);
294         if (gn != NULL) {
295             /*
296              * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
297              * are added to the list in the order in which they were
298              * encountered in the makefile.
299              */
300             Lst_AtEnd(nodes, gn);
301             if (gn->type & OP_DOUBLEDEP) {
302                 Lst_Concat(nodes, gn->cohorts, LST_CONCNEW);
303             }
304         } else if (flags == TARG_NOCREATE) {
305             Error("\"%s\" -- target unknown.", name);
306         }
307     }
308     Lst_Close(names);
309     return (nodes);
310 }
311
312 /*-
313  *-----------------------------------------------------------------------
314  * Targ_Ignore  --
315  *      Return true if should ignore errors when creating gn
316  *
317  * Results:
318  *      TRUE if should ignore errors
319  *
320  * Side Effects:
321  *      None
322  *-----------------------------------------------------------------------
323  */
324 Boolean
325 Targ_Ignore(GNode *gn)
326 {
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
351     if (beSilent || (gn->type & OP_SILENT)) {
352         return (TRUE);
353     } else {
354         return (FALSE);
355     }
356 }
357
358 /*-
359  *-----------------------------------------------------------------------
360  * Targ_Precious --
361  *      See if the given target is precious
362  *
363  * Results:
364  *      TRUE if it is precious. FALSE otherwise
365  *
366  * Side Effects:
367  *      None
368  *-----------------------------------------------------------------------
369  */
370 Boolean
371 Targ_Precious(GNode *gn)
372 {
373
374     if (allPrecious || (gn->type & (OP_PRECIOUS | OP_DOUBLEDEP))) {
375         return (TRUE);
376     } else {
377         return (FALSE);
378     }
379 }
380
381 /******************* DEBUG INFO PRINTING ****************/
382
383 static GNode      *mainTarg;    /* the main target, as set by Targ_SetMain */
384
385 /*-
386  *-----------------------------------------------------------------------
387  * Targ_SetMain --
388  *      Set our idea of the main target we'll be creating. Used for
389  *      debugging output.
390  *
391  * Results:
392  *      None.
393  *
394  * Side Effects:
395  *      "mainTarg" is set to the main target's node.
396  *-----------------------------------------------------------------------
397  */
398 void
399 Targ_SetMain(GNode *gn)
400 {
401
402     mainTarg = gn;
403 }
404
405 static int
406 TargPrintName(void *gnp, void *ppath)
407 {
408     GNode *gn = (GNode *) gnp;
409
410     printf("%s ", gn->name);
411 #ifdef notdef
412     if (ppath) {
413         if (gn->path) {
414             printf("[%s]  ", gn->path);
415         }
416         if (gn == mainTarg) {
417             printf("(MAIN NAME)  ");
418         }
419     }
420 #endif /* notdef */
421     return (ppath ? 0 : 0);
422 }
423
424
425 int
426 Targ_PrintCmd(void *cmd, void *dummy __unused)
427 {
428
429     printf("\t%s\n", (char *)cmd);
430     return (0);
431 }
432
433 /*-
434  *-----------------------------------------------------------------------
435  * Targ_FmtTime --
436  *      Format a modification time in some reasonable way and return it.
437  *
438  * Results:
439  *      The time reformatted.
440  *
441  * Side Effects:
442  *      The time is placed in a static area, so it is overwritten
443  *      with each call.
444  *
445  *-----------------------------------------------------------------------
446  */
447 char *
448 Targ_FmtTime(time_t modtime)
449 {
450     struct tm           *parts;
451     static char         buf[128];
452
453     parts = localtime(&modtime);
454
455     strftime(buf, sizeof buf, "%H:%M:%S %b %d, %Y", parts);
456     buf[sizeof(buf) - 1] = '\0';
457     return (buf);
458 }
459
460 /*-
461  *-----------------------------------------------------------------------
462  * Targ_PrintType --
463  *      Print out a type field giving only those attributes the user can
464  *      set.
465  *
466  * Results:
467  *
468  * Side Effects:
469  *
470  *-----------------------------------------------------------------------
471  */
472 void
473 Targ_PrintType(int type)
474 {
475     int    tbit;
476
477 #define PRINTBIT(attr)  case CONCAT(OP_,attr): printf("." #attr " "); break
478 #define PRINTDBIT(attr) case CONCAT(OP_,attr): DEBUGF(TARG, ("." #attr " ")); break
479
480     type &= ~OP_OPMASK;
481
482     while (type) {
483         tbit = 1 << (ffs(type) - 1);
484         type &= ~tbit;
485
486         switch(tbit) {
487             PRINTBIT(OPTIONAL);
488             PRINTBIT(USE);
489             PRINTBIT(EXEC);
490             PRINTBIT(IGNORE);
491             PRINTBIT(PRECIOUS);
492             PRINTBIT(SILENT);
493             PRINTBIT(MAKE);
494             PRINTBIT(JOIN);
495             PRINTBIT(INVISIBLE);
496             PRINTBIT(NOTMAIN);
497             PRINTDBIT(LIB);
498             /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
499             case OP_MEMBER: DEBUGF(TARG, (".MEMBER ")); break;
500             PRINTDBIT(ARCHV);
501         }
502     }
503 }
504
505 /*-
506  *-----------------------------------------------------------------------
507  * TargPrintNode --
508  *      print the contents of a node
509  *-----------------------------------------------------------------------
510  */
511 static int
512 TargPrintNode(void *gnp, void *passp)
513 {
514     GNode         *gn = gnp;
515     int           pass = *(int *)passp;
516
517     if (!OP_NOP(gn->type)) {
518         printf("#\n");
519         if (gn == mainTarg) {
520             printf("# *** MAIN TARGET ***\n");
521         }
522         if (pass == 2) {
523             if (gn->unmade) {
524                 printf("# %d unmade children\n", gn->unmade);
525             } else {
526                 printf("# No unmade children\n");
527             }
528             if (!(gn->type & (OP_JOIN | OP_USE | OP_EXEC))) {
529                 if (gn->mtime != 0) {
530                     printf("# last modified %s: %s\n",
531                               Targ_FmtTime(gn->mtime),
532                               (gn->made == UNMADE ? "unmade" :
533                                (gn->made == MADE ? "made" :
534                                 (gn->made == UPTODATE ? "up-to-date" :
535                                  "error when made"))));
536                 } else if (gn->made != UNMADE) {
537                     printf("# non-existent (maybe): %s\n",
538                               (gn->made == MADE ? "made" :
539                                (gn->made == UPTODATE ? "up-to-date" :
540                                 (gn->made == ERROR ? "error when made" :
541                                  "aborted"))));
542                 } else {
543                     printf("# unmade\n");
544                 }
545             }
546             if (!Lst_IsEmpty (gn->iParents)) {
547                 printf("# implicit parents: ");
548                 Lst_ForEach(gn->iParents, TargPrintName, (void *)NULL);
549                 fputc('\n', stdout);
550             }
551         }
552         if (!Lst_IsEmpty (gn->parents)) {
553             printf("# parents: ");
554             Lst_ForEach(gn->parents, TargPrintName, (void *)NULL);
555             fputc('\n', stdout);
556         }
557
558         printf("%-16s", gn->name);
559         switch (gn->type & OP_OPMASK) {
560             case OP_DEPENDS:
561                 printf(": "); break;
562             case OP_FORCE:
563                 printf("! "); break;
564             case OP_DOUBLEDEP:
565                 printf(":: "); break;
566             default:
567                 break;
568         }
569         Targ_PrintType(gn->type);
570         Lst_ForEach(gn->children, TargPrintName, (void *)NULL);
571         fputc('\n', stdout);
572         Lst_ForEach(gn->commands, Targ_PrintCmd, (void *)NULL);
573         printf("\n\n");
574         if (gn->type & OP_DOUBLEDEP) {
575             Lst_ForEach(gn->cohorts, TargPrintNode, &pass);
576         }
577     }
578     return (0);
579 }
580
581 /*-
582  *-----------------------------------------------------------------------
583  * TargPrintOnlySrc --
584  *      Print only those targets that are just a source.
585  *
586  * Results:
587  *      0.
588  *
589  * Side Effects:
590  *      The name of each file is printed preceded by #\t
591  *
592  *-----------------------------------------------------------------------
593  */
594 static int
595 TargPrintOnlySrc(void *gnp, void *dummy __unused)
596 {
597     GNode         *gn = gnp;
598
599     if (OP_NOP(gn->type))
600         printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
601
602     return (0);
603 }
604
605 /*-
606  *-----------------------------------------------------------------------
607  * Targ_PrintGraph --
608  *      Print the entire graph.
609  *
610  * Results:
611  *      none
612  *
613  * Side Effects:
614  *      lots o' output
615  *-----------------------------------------------------------------------
616  */
617 void
618 Targ_PrintGraph(int pass)
619 {
620
621     printf("#*** Input graph:\n");
622     Lst_ForEach(allTargets, TargPrintNode, &pass);
623     printf("\n\n");
624     printf("#\n#   Files that are only sources:\n");
625     Lst_ForEach(allTargets, TargPrintOnlySrc, (void *)NULL);
626     printf("#*** Global Variables:\n");
627     Var_Dump(VAR_GLOBAL);
628     printf("#*** Command-line Variables:\n");
629     Var_Dump(VAR_CMD);
630     printf("\n");
631     Dir_PrintDirectories();
632     printf("\n");
633     Suff_PrintAll();
634 }