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