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