VirtualBox

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

Last change on this file since 151 was 51, checked in by bird, 22 years ago

kMk and porting to kLib.

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

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