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