VirtualBox

source: kBuild/trunk/src/kmk/targ.c@ 30

Last change on this file since 30 was 25, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r24,
which included commits to RCS files with non-trunk default branches.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette