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