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