targ.c revision 138916
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 138916 2004-12-16 16:14:16Z 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
91/* the list of all targets found so far */
92static Lst allTargets = Lst_Initializer(allTargets);
93
94static Hash_Table targets;	/* a hash table of same */
95
96#define	HTSIZE	191		/* initial size of hash table */
97
98static int TargPrintOnlySrc(void *, void *);
99static int TargPrintName(void *, void *);
100static int TargPrintNode(void *, 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    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
137    Lst_Destroy(&allTargets, NOFREE);
138    Hash_DeleteTable(&targets);
139}
140
141/*-
142 *-----------------------------------------------------------------------
143 * Targ_NewGN  --
144 *	Create and initialize a new graph node
145 *
146 * Results:
147 *	An initialized graph node with the name field filled with a copy
148 *	of the passed name
149 *
150 * Side Effects:
151 *	The gnode is added to the list of all gnodes.
152 *-----------------------------------------------------------------------
153 */
154GNode *
155Targ_NewGN(char *name)
156{
157    GNode *gn;
158
159    gn = emalloc(sizeof(GNode));
160    gn->name = estrdup(name);
161    gn->path = NULL;
162    if (name[0] == '-' && name[1] == 'l') {
163	gn->type = OP_LIB;
164    } else {
165	gn->type = 0;
166    }
167    gn->unmade = 0;
168    gn->make = FALSE;
169    gn->made = UNMADE;
170    gn->childMade = FALSE;
171    gn->order = 0;
172    gn->mtime = gn->cmtime = 0;
173    Lst_Init(&gn->iParents);
174    Lst_Init(&gn->cohorts);
175    Lst_Init(&gn->parents);
176    Lst_Init(&gn->children);
177    Lst_Init(&gn->successors);
178    Lst_Init(&gn->preds);
179    Lst_Init(&gn->context);
180    Lst_Init(&gn->commands);
181    gn->suffix = NULL;
182
183    return (gn);
184}
185
186/*-
187 *-----------------------------------------------------------------------
188 * Targ_FindNode  --
189 *	Find a node in the list using the given name for matching
190 *
191 * Results:
192 *	The node in the list if it was. If it wasn't, return NULL of
193 *	flags was TARG_NOCREATE or the newly created and initialized node
194 *	if it was TARG_CREATE
195 *
196 * Side Effects:
197 *	Sometimes a node is created and added to the list
198 *-----------------------------------------------------------------------
199 */
200GNode *
201Targ_FindNode(char *name, int flags)
202{
203    GNode         *gn;	      /* node in that element */
204    Hash_Entry	  *he;	      /* New or used hash entry for node */
205    Boolean	  isNew;      /* Set TRUE if Hash_CreateEntry had to create */
206			      /* an entry for the node */
207
208    if (flags & TARG_CREATE) {
209	he = Hash_CreateEntry(&targets, name, &isNew);
210	if (isNew) {
211	    gn = Targ_NewGN(name);
212	    Hash_SetValue (he, gn);
213	    Lst_AtEnd(&allTargets, gn);
214	}
215    } else {
216	he = Hash_FindEntry(&targets, name);
217    }
218
219    if (he == NULL) {
220	return (NULL);
221    } else {
222	return (Hash_GetValue(he));
223    }
224}
225
226/*-
227 *-----------------------------------------------------------------------
228 * Targ_FindList --
229 *	Make a complete list of GNodes from the given list of names
230 *
231 * Results:
232 *	A complete list of graph nodes corresponding to all instances of all
233 *	the names in names.
234 *
235 * Side Effects:
236 *	If flags is TARG_CREATE, nodes will be created for all names in
237 *	names which do not yet have graph nodes. If flags is TARG_NOCREATE,
238 *	an error message will be printed for each name which can't be found.
239 * -----------------------------------------------------------------------
240 */
241void
242Targ_FindList(Lst *nodes, Lst *names, int flags)
243{
244    LstNode	   *ln;		/* name list element */
245    GNode	   *gn;		/* node in tLn */
246    char    	   *name;
247
248    for (ln = Lst_First(names); ln != NULL; ln = Lst_Succ(ln)) {
249	name = Lst_Datum(ln);
250	gn = Targ_FindNode(name, flags);
251	if (gn != NULL) {
252	    /*
253	     * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
254	     * are added to the list in the order in which they were
255	     * encountered in the makefile.
256	     */
257	    Lst_AtEnd(nodes, gn);
258	    if (gn->type & OP_DOUBLEDEP) {
259		Lst_Concat(nodes, &gn->cohorts, LST_CONCNEW);
260	    }
261	} else if (flags == TARG_NOCREATE) {
262	    Error("\"%s\" -- target unknown.", name);
263	}
264    }
265}
266
267/*-
268 *-----------------------------------------------------------------------
269 * Targ_Ignore  --
270 *	Return true if should ignore errors when creating gn
271 *
272 * Results:
273 *	TRUE if should ignore errors
274 *
275 * Side Effects:
276 *	None
277 *-----------------------------------------------------------------------
278 */
279Boolean
280Targ_Ignore(GNode *gn)
281{
282
283    if (ignoreErrors || (gn->type & OP_IGNORE)) {
284	return (TRUE);
285    } else {
286	return (FALSE);
287    }
288}
289
290/*-
291 *-----------------------------------------------------------------------
292 * Targ_Silent  --
293 *	Return true if be silent when creating gn
294 *
295 * Results:
296 *	TRUE if should be silent
297 *
298 * Side Effects:
299 *	None
300 *-----------------------------------------------------------------------
301 */
302Boolean
303Targ_Silent(GNode *gn)
304{
305
306    if (beSilent || (gn->type & OP_SILENT)) {
307	return (TRUE);
308    } else {
309	return (FALSE);
310    }
311}
312
313/*-
314 *-----------------------------------------------------------------------
315 * Targ_Precious --
316 *	See if the given target is precious
317 *
318 * Results:
319 *	TRUE if it is precious. FALSE otherwise
320 *
321 * Side Effects:
322 *	None
323 *-----------------------------------------------------------------------
324 */
325Boolean
326Targ_Precious(GNode *gn)
327{
328
329    if (allPrecious || (gn->type & (OP_PRECIOUS | OP_DOUBLEDEP))) {
330	return (TRUE);
331    } else {
332	return (FALSE);
333    }
334}
335
336/******************* DEBUG INFO PRINTING ****************/
337
338static GNode	  *mainTarg;	/* the main target, as set by Targ_SetMain */
339
340/*-
341 *-----------------------------------------------------------------------
342 * Targ_SetMain --
343 *	Set our idea of the main target we'll be creating. Used for
344 *	debugging output.
345 *
346 * Results:
347 *	None.
348 *
349 * Side Effects:
350 *	"mainTarg" is set to the main target's node.
351 *-----------------------------------------------------------------------
352 */
353void
354Targ_SetMain(GNode *gn)
355{
356
357    mainTarg = gn;
358}
359
360static int
361TargPrintName(void *gnp, void *ppath)
362{
363    GNode *gn = (GNode *) gnp;
364
365    printf("%s ", gn->name);
366#ifdef notdef
367    if (ppath) {
368	if (gn->path) {
369	    printf("[%s]  ", gn->path);
370	}
371	if (gn == mainTarg) {
372	    printf("(MAIN NAME)  ");
373	}
374    }
375#endif /* notdef */
376    return (ppath ? 0 : 0);
377}
378
379
380int
381Targ_PrintCmd(void *cmd, void *dummy __unused)
382{
383
384    printf("\t%s\n", (char *)cmd);
385    return (0);
386}
387
388/*-
389 *-----------------------------------------------------------------------
390 * Targ_FmtTime --
391 *	Format a modification time in some reasonable way and return it.
392 *
393 * Results:
394 *	The time reformatted.
395 *
396 * Side Effects:
397 *	The time is placed in a static area, so it is overwritten
398 *	with each call.
399 *
400 *-----------------------------------------------------------------------
401 */
402char *
403Targ_FmtTime(time_t modtime)
404{
405    struct tm	  	*parts;
406    static char	  	buf[128];
407
408    parts = localtime(&modtime);
409
410    strftime(buf, sizeof buf, "%H:%M:%S %b %d, %Y", parts);
411    buf[sizeof(buf) - 1] = '\0';
412    return (buf);
413}
414
415/*-
416 *-----------------------------------------------------------------------
417 * Targ_PrintType --
418 *	Print out a type field giving only those attributes the user can
419 *	set.
420 *
421 * Results:
422 *
423 * Side Effects:
424 *
425 *-----------------------------------------------------------------------
426 */
427void
428Targ_PrintType(int type)
429{
430    int    tbit;
431
432#define	PRINTBIT(attr)	case CONCAT(OP_,attr): printf("." #attr " "); break
433#define	PRINTDBIT(attr) case CONCAT(OP_,attr): DEBUGF(TARG, ("." #attr " ")); break
434
435    type &= ~OP_OPMASK;
436
437    while (type) {
438	tbit = 1 << (ffs(type) - 1);
439	type &= ~tbit;
440
441	switch(tbit) {
442	    PRINTBIT(OPTIONAL);
443	    PRINTBIT(USE);
444	    PRINTBIT(EXEC);
445	    PRINTBIT(IGNORE);
446	    PRINTBIT(PRECIOUS);
447	    PRINTBIT(SILENT);
448	    PRINTBIT(MAKE);
449	    PRINTBIT(JOIN);
450	    PRINTBIT(INVISIBLE);
451	    PRINTBIT(NOTMAIN);
452	    PRINTDBIT(LIB);
453	    /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
454	    case OP_MEMBER: DEBUGF(TARG, (".MEMBER ")); break;
455	    PRINTDBIT(ARCHV);
456	}
457    }
458}
459
460/*-
461 *-----------------------------------------------------------------------
462 * TargPrintNode --
463 *	print the contents of a node
464 *-----------------------------------------------------------------------
465 */
466static int
467TargPrintNode(void *gnp, void *passp)
468{
469    GNode         *gn = gnp;
470    int	    	  pass = *(int *)passp;
471
472    if (!OP_NOP(gn->type)) {
473	printf("#\n");
474	if (gn == mainTarg) {
475	    printf("# *** MAIN TARGET ***\n");
476	}
477	if (pass == 2) {
478	    if (gn->unmade) {
479		printf("# %d unmade children\n", gn->unmade);
480	    } else {
481		printf("# No unmade children\n");
482	    }
483	    if (!(gn->type & (OP_JOIN | OP_USE | OP_EXEC))) {
484		if (gn->mtime != 0) {
485		    printf("# last modified %s: %s\n",
486			      Targ_FmtTime(gn->mtime),
487			      (gn->made == UNMADE ? "unmade" :
488			       (gn->made == MADE ? "made" :
489				(gn->made == UPTODATE ? "up-to-date" :
490				 "error when made"))));
491		} else if (gn->made != UNMADE) {
492		    printf("# non-existent (maybe): %s\n",
493			      (gn->made == MADE ? "made" :
494			       (gn->made == UPTODATE ? "up-to-date" :
495				(gn->made == ERROR ? "error when made" :
496				 "aborted"))));
497		} else {
498		    printf("# unmade\n");
499		}
500	    }
501	    if (!Lst_IsEmpty(&gn->iParents)) {
502		printf("# implicit parents: ");
503		Lst_ForEach(&gn->iParents, TargPrintName, (void *)NULL);
504		fputc('\n', stdout);
505	    }
506	}
507	if (!Lst_IsEmpty(&gn->parents)) {
508	    printf("# parents: ");
509	    Lst_ForEach(&gn->parents, TargPrintName, (void *)NULL);
510	    fputc('\n', stdout);
511	}
512
513	printf("%-16s", gn->name);
514	switch (gn->type & OP_OPMASK) {
515	    case OP_DEPENDS:
516		printf(": "); break;
517	    case OP_FORCE:
518		printf("! "); break;
519	    case OP_DOUBLEDEP:
520		printf(":: "); break;
521	    default:
522		break;
523	}
524	Targ_PrintType(gn->type);
525	Lst_ForEach(&gn->children, TargPrintName, (void *)NULL);
526	fputc('\n', stdout);
527	Lst_ForEach(&gn->commands, Targ_PrintCmd, (void *)NULL);
528	printf("\n\n");
529	if (gn->type & OP_DOUBLEDEP) {
530	    Lst_ForEach(&gn->cohorts, TargPrintNode, &pass);
531	}
532    }
533    return (0);
534}
535
536/*-
537 *-----------------------------------------------------------------------
538 * TargPrintOnlySrc --
539 *	Print only those targets that are just a source.
540 *
541 * Results:
542 *	0.
543 *
544 * Side Effects:
545 *	The name of each file is printed preceded by #\t
546 *
547 *-----------------------------------------------------------------------
548 */
549static int
550TargPrintOnlySrc(void *gnp, void *dummy __unused)
551{
552    GNode   	  *gn = gnp;
553
554    if (OP_NOP(gn->type))
555	printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
556
557    return (0);
558}
559
560/*-
561 *-----------------------------------------------------------------------
562 * Targ_PrintGraph --
563 *	Print the entire graph.
564 *
565 * Results:
566 *	none
567 *
568 * Side Effects:
569 *	lots o' output
570 *-----------------------------------------------------------------------
571 */
572void
573Targ_PrintGraph(int pass)
574{
575
576    printf("#*** Input graph:\n");
577    Lst_ForEach(&allTargets, TargPrintNode, &pass);
578    printf("\n\n");
579    printf("#\n#   Files that are only sources:\n");
580    Lst_ForEach(&allTargets, TargPrintOnlySrc, (void *)NULL);
581    printf("#*** Global Variables:\n");
582    Var_Dump(VAR_GLOBAL);
583    printf("#*** Command-line Variables:\n");
584    Var_Dump(VAR_CMD);
585    printf("\n");
586    Dir_PrintDirectories();
587    printf("\n");
588    Suff_PrintAll();
589}
590