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