source: trunk/src/kmk/targ.c@ 9

Last change on this file since 9 was 9, checked in by bird, 23 years ago

Initial revision

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.4 KB
Line 
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: src/usr.bin/make/targ.c,v 1.25 2002/10/09 03:42:10 jmallett Exp $");
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 allTargets = Lst_Init (FALSE);
118 Hash_InitTable (&targets, HTSIZE);
119}
120
121/*-
122 *-----------------------------------------------------------------------
123 * Targ_End --
124 * Finalize this module
125 *
126 * Results:
127 * None
128 *
129 * Side Effects:
130 * All lists and gnodes are cleared
131 *-----------------------------------------------------------------------
132 */
133void
134Targ_End (void)
135{
136 Lst_Destroy(allTargets, NOFREE);
137 if (allGNs)
138 Lst_Destroy(allGNs, TargFreeGN);
139 Hash_DeleteTable(&targets);
140}
141
142/*-
143 *-----------------------------------------------------------------------
144 * Targ_NewGN --
145 * Create and initialize a new graph node
146 *
147 * Results:
148 * An initialized graph node with the name field filled with a copy
149 * of the passed name
150 *
151 * Side Effects:
152 * The gnode is added to the list of all gnodes.
153 *-----------------------------------------------------------------------
154 */
155GNode *
156Targ_NewGN (char *name)
157{
158 GNode *gn;
159
160 gn = (GNode *) emalloc (sizeof (GNode));
161 gn->name = estrdup (name);
162 gn->path = (char *) 0;
163 if (name[0] == '-' && name[1] == 'l') {
164 gn->type = OP_LIB;
165 } else {
166 gn->type = 0;
167 }
168 gn->unmade = 0;
169 gn->make = FALSE;
170 gn->made = UNMADE;
171 gn->childMade = FALSE;
172 gn->order = 0;
173 gn->mtime = gn->cmtime = 0;
174 gn->iParents = Lst_Init (FALSE);
175 gn->cohorts = Lst_Init (FALSE);
176 gn->parents = Lst_Init (FALSE);
177 gn->children = Lst_Init (FALSE);
178 gn->successors = Lst_Init (FALSE);
179 gn->preds = Lst_Init (FALSE);
180 gn->context = Lst_Init (FALSE);
181 gn->commands = Lst_Init (FALSE);
182 gn->suffix = NULL;
183
184 if (allGNs == NULL)
185 allGNs = Lst_Init(FALSE);
186 Lst_AtEnd(allGNs, (void *) gn);
187
188 return (gn);
189}
190
191/*-
192 *-----------------------------------------------------------------------
193 * TargFreeGN --
194 * Destroy a GNode
195 *
196 * Results:
197 * None.
198 *
199 * Side Effects:
200 * None.
201 *-----------------------------------------------------------------------
202 */
203static void
204TargFreeGN (void *gnp)
205{
206 GNode *gn = (GNode *) gnp;
207
208
209 free(gn->name);
210 efree(gn->path);
211
212 Lst_Destroy(gn->iParents, NOFREE);
213 Lst_Destroy(gn->cohorts, NOFREE);
214 Lst_Destroy(gn->parents, NOFREE);
215 Lst_Destroy(gn->children, NOFREE);
216 Lst_Destroy(gn->successors, NOFREE);
217 Lst_Destroy(gn->preds, NOFREE);
218 Lst_Destroy(gn->context, NOFREE);
219 Lst_Destroy(gn->commands, NOFREE);
220 free(gn);
221}
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
247 if (flags & TARG_CREATE) {
248 he = Hash_CreateEntry (&targets, name, &isNew);
249 if (isNew) {
250 gn = Targ_NewGN (name);
251 Hash_SetValue (he, gn);
252 (void) Lst_AtEnd (allTargets, (void *)gn);
253 }
254 } else {
255 he = Hash_FindEntry (&targets, name);
256 }
257
258 if (he == (Hash_Entry *) NULL) {
259 return (NULL);
260 } else {
261 return ((GNode *) Hash_GetValue (he));
262 }
263}
264
265/*-
266 *-----------------------------------------------------------------------
267 * Targ_FindList --
268 * Make a complete list of GNodes from the given list of names
269 *
270 * Results:
271 * A complete list of graph nodes corresponding to all instances of all
272 * the names in names.
273 *
274 * Side Effects:
275 * If flags is TARG_CREATE, nodes will be created for all names in
276 * names which do not yet have graph nodes. If flags is TARG_NOCREATE,
277 * an error message will be printed for each name which can't be found.
278 * -----------------------------------------------------------------------
279 */
280Lst
281Targ_FindList (Lst names, int flags)
282{
283 Lst nodes; /* result list */
284 LstNode ln; /* name list element */
285 GNode *gn; /* node in tLn */
286 char *name;
287
288 nodes = Lst_Init (FALSE);
289
290 if (Lst_Open (names) == FAILURE) {
291 return (nodes);
292 }
293 while ((ln = Lst_Next (names)) != NULL) {
294 name = (char *)Lst_Datum(ln);
295 gn = Targ_FindNode (name, flags);
296 if (gn != NULL) {
297 /*
298 * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
299 * are added to the list in the order in which they were
300 * encountered in the makefile.
301 */
302 (void) Lst_AtEnd (nodes, (void *)gn);
303 if (gn->type & OP_DOUBLEDEP) {
304 (void)Lst_Concat (nodes, gn->cohorts, LST_CONCNEW);
305 }
306 } else if (flags == TARG_NOCREATE) {
307 Error ("\"%s\" -- target unknown.", name);
308 }
309 }
310 Lst_Close (names);
311 return (nodes);
312}
313
314/*-
315 *-----------------------------------------------------------------------
316 * Targ_Ignore --
317 * Return true if should ignore errors when creating gn
318 *
319 * Results:
320 * TRUE if should ignore errors
321 *
322 * Side Effects:
323 * None
324 *-----------------------------------------------------------------------
325 */
326Boolean
327Targ_Ignore (GNode *gn)
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 if (beSilent || gn->type & OP_SILENT) {
352 return (TRUE);
353 } else {
354 return (FALSE);
355 }
356}
357
358/*-
359 *-----------------------------------------------------------------------
360 * Targ_Precious --
361 * See if the given target is precious
362 *
363 * Results:
364 * TRUE if it is precious. FALSE otherwise
365 *
366 * Side Effects:
367 * None
368 *-----------------------------------------------------------------------
369 */
370Boolean
371Targ_Precious (GNode *gn)
372{
373 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) {
374 return (TRUE);
375 } else {
376 return (FALSE);
377 }
378}
379
380/******************* DEBUG INFO PRINTING ****************/
381
382static GNode *mainTarg; /* the main target, as set by Targ_SetMain */
383/*-
384 *-----------------------------------------------------------------------
385 * Targ_SetMain --
386 * Set our idea of the main target we'll be creating. Used for
387 * debugging output.
388 *
389 * Results:
390 * None.
391 *
392 * Side Effects:
393 * "mainTarg" is set to the main target's node.
394 *-----------------------------------------------------------------------
395 */
396void
397Targ_SetMain (GNode *gn)
398{
399 mainTarg = gn;
400}
401
402static int
403TargPrintName (void *gnp, void *ppath)
404{
405 GNode *gn = (GNode *) gnp;
406 printf ("%s ", gn->name);
407#ifdef notdef
408 if (ppath) {
409 if (gn->path) {
410 printf ("[%s] ", gn->path);
411 }
412 if (gn == mainTarg) {
413 printf ("(MAIN NAME) ");
414 }
415 }
416#endif /* notdef */
417 return (ppath ? 0 : 0);
418}
419
420
421int
422Targ_PrintCmd (void *cmd, void *dummy __unused)
423{
424 printf ("\t%s\n", (char *) cmd);
425 return (0);
426}
427
428/*-
429 *-----------------------------------------------------------------------
430 * Targ_FmtTime --
431 * Format a modification time in some reasonable way and return it.
432 *
433 * Results:
434 * The time reformatted.
435 *
436 * Side Effects:
437 * The time is placed in a static area, so it is overwritten
438 * with each call.
439 *
440 *-----------------------------------------------------------------------
441 */
442char *
443Targ_FmtTime (time_t modtime)
444{
445 struct tm *parts;
446 static char buf[128];
447
448 parts = localtime(&modtime);
449
450 strftime(buf, sizeof buf, "%H:%M:%S %b %d, %Y", parts);
451 buf[sizeof(buf) - 1] = '\0';
452 return(buf);
453}
454
455/*-
456 *-----------------------------------------------------------------------
457 * Targ_PrintType --
458 * Print out a type field giving only those attributes the user can
459 * set.
460 *
461 * Results:
462 *
463 * Side Effects:
464 *
465 *-----------------------------------------------------------------------
466 */
467void
468Targ_PrintType (int type)
469{
470 int tbit;
471
472#define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break
473#define PRINTDBIT(attr) case CONCAT(OP_,attr): DEBUGF(TARG, ("." #attr " ")); break
474
475 type &= ~OP_OPMASK;
476
477 while (type) {
478 tbit = 1 << (ffs(type) - 1);
479 type &= ~tbit;
480
481 switch(tbit) {
482 PRINTBIT(OPTIONAL);
483 PRINTBIT(USE);
484 PRINTBIT(EXEC);
485 PRINTBIT(IGNORE);
486 PRINTBIT(PRECIOUS);
487 PRINTBIT(SILENT);
488 PRINTBIT(MAKE);
489 PRINTBIT(JOIN);
490 PRINTBIT(INVISIBLE);
491 PRINTBIT(NOTMAIN);
492 PRINTDBIT(LIB);
493 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
494 case OP_MEMBER: DEBUGF(TARG, (".MEMBER ")); break;
495 PRINTDBIT(ARCHV);
496 }
497 }
498}
499
500/*-
501 *-----------------------------------------------------------------------
502 * TargPrintNode --
503 * print the contents of a node
504 *-----------------------------------------------------------------------
505 */
506static int
507TargPrintNode (void *gnp, void *passp)
508{
509 GNode *gn = (GNode *) gnp;
510 int pass = *(int *) passp;
511 if (!OP_NOP(gn->type)) {
512 printf("#\n");
513 if (gn == mainTarg) {
514 printf("# *** MAIN TARGET ***\n");
515 }
516 if (pass == 2) {
517 if (gn->unmade) {
518 printf("# %d unmade children\n", gn->unmade);
519 } else {
520 printf("# No unmade children\n");
521 }
522 if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
523 if (gn->mtime != 0) {
524 printf("# last modified %s: %s\n",
525 Targ_FmtTime(gn->mtime),
526 (gn->made == UNMADE ? "unmade" :
527 (gn->made == MADE ? "made" :
528 (gn->made == UPTODATE ? "up-to-date" :
529 "error when made"))));
530 } else if (gn->made != UNMADE) {
531 printf("# non-existent (maybe): %s\n",
532 (gn->made == MADE ? "made" :
533 (gn->made == UPTODATE ? "up-to-date" :
534 (gn->made == ERROR ? "error when made" :
535 "aborted"))));
536 } else {
537 printf("# unmade\n");
538 }
539 }
540 if (!Lst_IsEmpty (gn->iParents)) {
541 printf("# implicit parents: ");
542 Lst_ForEach (gn->iParents, TargPrintName, (void *)0);
543 fputc ('\n', stdout);
544 }
545 }
546 if (!Lst_IsEmpty (gn->parents)) {
547 printf("# parents: ");
548 Lst_ForEach (gn->parents, TargPrintName, (void *)0);
549 fputc ('\n', stdout);
550 }
551
552 printf("%-16s", gn->name);
553 switch (gn->type & OP_OPMASK) {
554 case OP_DEPENDS:
555 printf(": "); break;
556 case OP_FORCE:
557 printf("! "); break;
558 case OP_DOUBLEDEP:
559 printf(":: "); break;
560 default:
561 break;
562 }
563 Targ_PrintType (gn->type);
564 Lst_ForEach (gn->children, TargPrintName, (void *)0);
565 fputc ('\n', stdout);
566 Lst_ForEach (gn->commands, Targ_PrintCmd, (void *)0);
567 printf("\n\n");
568 if (gn->type & OP_DOUBLEDEP) {
569 Lst_ForEach (gn->cohorts, TargPrintNode, (void *)&pass);
570 }
571 }
572 return (0);
573}
574
575/*-
576 *-----------------------------------------------------------------------
577 * TargPrintOnlySrc --
578 * Print only those targets that are just a source.
579 *
580 * Results:
581 * 0.
582 *
583 * Side Effects:
584 * The name of each file is printed preceded by #\t
585 *
586 *-----------------------------------------------------------------------
587 */
588static int
589TargPrintOnlySrc(void *gnp, void *dummy __unused)
590{
591 GNode *gn = (GNode *) gnp;
592 if (OP_NOP(gn->type))
593 printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
594
595 return (0);
596}
597
598/*-
599 *-----------------------------------------------------------------------
600 * Targ_PrintGraph --
601 * Print the entire graph.
602 *
603 * Results:
604 * none
605 *
606 * Side Effects:
607 * lots o' output
608 *-----------------------------------------------------------------------
609 */
610void
611Targ_PrintGraph (int pass)
612{
613 printf("#*** Input graph:\n");
614 Lst_ForEach (allTargets, TargPrintNode, (void *)&pass);
615 printf("\n\n");
616 printf("#\n# Files that are only sources:\n");
617 Lst_ForEach (allTargets, TargPrintOnlySrc, (void *) 0);
618 printf("#*** Global Variables:\n");
619 Var_Dump (VAR_GLOBAL);
620 printf("#*** Command-line Variables:\n");
621 Var_Dump (VAR_CMD);
622 printf("\n");
623 Dir_PrintDirectories();
624 printf("\n");
625 Suff_PrintAll();
626}
Note: See TracBrowser for help on using the repository browser.