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