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