1 /* $NetBSD: targ.c,v 1.135 2020/11/16 22:28:44 rillig Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1989, 1990, 1993 5 * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 /* 36 * Copyright (c) 1989 by Berkeley Softworks 37 * All rights reserved. 38 * 39 * This code is derived from software contributed to Berkeley by 40 * Adam de Boor. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by the University of 53 * California, Berkeley and its contributors. 54 * 4. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 */ 70 71 /* 72 * Maintaining the targets and sources, which are both implemented as GNode. 73 * 74 * Interface: 75 * Targ_Init Initialize the module. 76 * 77 * Targ_End Clean up the module. 78 * 79 * Targ_List Return the list of all targets so far. 80 * 81 * GNode_New Create a new GNode for the passed target 82 * (string). The node is *not* placed in the 83 * hash table, though all its fields are 84 * initialized. 85 * 86 * Targ_FindNode Find the node, or return NULL. 87 * 88 * Targ_GetNode Find the node, or create it. 89 * 90 * Targ_NewInternalNode 91 * Create an internal node. 92 * 93 * Targ_FindList Given a list of names, find nodes for all 94 * of them, creating them as necessary. 95 * 96 * Targ_Ignore Return TRUE if errors should be ignored when 97 * creating the given target. 98 * 99 * Targ_Silent Return TRUE if we should be silent when 100 * creating the given target. 101 * 102 * Targ_Precious Return TRUE if the target is precious and 103 * should not be removed if we are interrupted. 104 * 105 * Targ_Propagate Propagate information between related nodes. 106 * Should be called after the makefiles are parsed 107 * but before any action is taken. 108 * 109 * Debugging: 110 * Targ_PrintGraph 111 * Print out the entire graphm all variables and 112 * statistics for the directory cache. Should print 113 * something for suffixes, too, but... 114 */ 115 116 #include <time.h> 117 118 #include "make.h" 119 #include "dir.h" 120 121 /* "@(#)targ.c 8.2 (Berkeley) 3/19/94" */ 122 MAKE_RCSID("$NetBSD: targ.c,v 1.135 2020/11/16 22:28:44 rillig Exp $"); 123 124 /* All target nodes found so far, but not the source nodes. */ 125 static GNodeList *allTargets; 126 static HashTable allTargetsByName; 127 128 #ifdef CLEANUP 129 static GNodeList *allNodes; 130 131 static void GNode_Free(void *); 132 #endif 133 134 void 135 Targ_Init(void) 136 { 137 allTargets = Lst_New(); 138 HashTable_Init(&allTargetsByName); 139 #ifdef CLEANUP 140 allNodes = Lst_New(); 141 #endif 142 } 143 144 void 145 Targ_End(void) 146 { 147 Targ_Stats(); 148 #ifdef CLEANUP 149 Lst_Free(allTargets); 150 HashTable_Done(&allTargetsByName); 151 Lst_Destroy(allNodes, GNode_Free); 152 #endif 153 } 154 155 void 156 Targ_Stats(void) 157 { 158 HashTable_DebugStats(&allTargetsByName, "targets"); 159 } 160 161 /* 162 * Return the list of all targets, which are all nodes that appear on the 163 * left-hand side of a dependency declaration such as "target: source". 164 * The returned list does not contain pure sources. 165 */ 166 GNodeList * 167 Targ_List(void) 168 { 169 return allTargets; 170 } 171 172 /* Create a new graph node, but don't register it anywhere. 173 * 174 * Graph nodes that appear on the left-hand side of a dependency line such 175 * as "target: source" are called targets. XXX: In some cases (like the 176 * .ALLTARGETS variable), all nodes are called targets as well, even if they 177 * never appear on the left-hand side. This is a mistake. 178 * 179 * Typical names for graph nodes are: 180 * "src.c" (an ordinary file) 181 * "clean" (a .PHONY target) 182 * ".END" (a special hook target) 183 * "-lm" (a library) 184 * "libc.a(isspace.o)" (an archive member) 185 */ 186 GNode * 187 GNode_New(const char *name) 188 { 189 GNode *gn; 190 191 gn = bmake_malloc(sizeof *gn); 192 gn->name = bmake_strdup(name); 193 gn->uname = NULL; 194 gn->path = NULL; 195 gn->type = name[0] == '-' && name[1] == 'l' ? OP_LIB : 0; 196 gn->flags = 0; 197 gn->made = UNMADE; 198 gn->unmade = 0; 199 gn->mtime = 0; 200 gn->youngestChild = NULL; 201 gn->implicitParents = Lst_New(); 202 gn->parents = Lst_New(); 203 gn->children = Lst_New(); 204 gn->order_pred = Lst_New(); 205 gn->order_succ = Lst_New(); 206 gn->cohorts = Lst_New(); 207 gn->cohort_num[0] = '\0'; 208 gn->unmade_cohorts = 0; 209 gn->centurion = NULL; 210 gn->checked_seqno = 0; 211 HashTable_Init(&gn->context); 212 gn->commands = Lst_New(); 213 gn->suffix = NULL; 214 gn->fname = NULL; 215 gn->lineno = 0; 216 217 #ifdef CLEANUP 218 Lst_Append(allNodes, gn); 219 #endif 220 221 return gn; 222 } 223 224 #ifdef CLEANUP 225 static void 226 GNode_Free(void *gnp) 227 { 228 GNode *gn = gnp; 229 230 free(gn->name); 231 free(gn->uname); 232 free(gn->path); 233 /* gn->youngestChild is not owned by this node. */ 234 Lst_Free(gn->implicitParents); /* ... but not the nodes themselves, */ 235 Lst_Free(gn->parents); /* as they are not owned by this node. */ 236 Lst_Free(gn->children); /* likewise */ 237 Lst_Free(gn->order_pred); /* likewise */ 238 Lst_Free(gn->order_succ); /* likewise */ 239 Lst_Free(gn->cohorts); /* likewise */ 240 HashTable_Done(&gn->context); /* ... but not the variables themselves, 241 * even though they are owned by this node. 242 * XXX: they should probably be freed. */ 243 Lst_Free(gn->commands); /* ... but not the commands themselves, 244 * as they may be shared with other nodes. */ 245 /* gn->suffix is not owned by this node. */ 246 /* XXX: gn->suffix should be unreferenced here. This requires a thorough 247 * check that the reference counting is done correctly in all places, 248 * otherwise a suffix might be freed too early. */ 249 250 free(gn); 251 } 252 #endif 253 254 /* Get the existing global node, or return NULL. */ 255 GNode * 256 Targ_FindNode(const char *name) 257 { 258 return HashTable_FindValue(&allTargetsByName, name); 259 } 260 261 /* Get the existing global node, or create it. */ 262 GNode * 263 Targ_GetNode(const char *name) 264 { 265 Boolean isNew; 266 HashEntry *he = HashTable_CreateEntry(&allTargetsByName, name, &isNew); 267 if (!isNew) 268 return HashEntry_Get(he); 269 270 { 271 GNode *gn = Targ_NewInternalNode(name); 272 HashEntry_Set(he, gn); 273 return gn; 274 } 275 } 276 277 /* 278 * Create a node, register it in .ALLTARGETS but don't store it in the 279 * table of global nodes. This means it cannot be found by name. 280 * 281 * This is used for internal nodes, such as cohorts or .WAIT nodes. 282 */ 283 GNode * 284 Targ_NewInternalNode(const char *name) 285 { 286 GNode *gn = GNode_New(name); 287 Var_Append(".ALLTARGETS", name, VAR_GLOBAL); 288 Lst_Append(allTargets, gn); 289 if (doing_depend) 290 gn->flags |= FROM_DEPEND; 291 return gn; 292 } 293 294 /* 295 * Return the .END node, which contains the commands to be run when 296 * everything else has been made. 297 */ 298 GNode *Targ_GetEndNode(void) 299 { 300 /* Save the node locally to avoid having to search for it all the time. */ 301 static GNode *endNode = NULL; 302 if (endNode == NULL) { 303 endNode = Targ_GetNode(".END"); 304 endNode->type = OP_SPECIAL; 305 } 306 return endNode; 307 } 308 309 /* Return the named nodes, creating them as necessary. */ 310 GNodeList * 311 Targ_FindList(StringList *names) 312 { 313 StringListNode *ln; 314 GNodeList *nodes = Lst_New(); 315 for (ln = names->first; ln != NULL; ln = ln->next) { 316 const char *name = ln->datum; 317 GNode *gn = Targ_GetNode(name); 318 Lst_Append(nodes, gn); 319 } 320 return nodes; 321 } 322 323 /* Return true if should ignore errors when creating gn. */ 324 Boolean 325 Targ_Ignore(const GNode *gn) 326 { 327 return opts.ignoreErrors || gn->type & OP_IGNORE; 328 } 329 330 /* Return true if be silent when creating gn. */ 331 Boolean 332 Targ_Silent(const GNode *gn) 333 { 334 return opts.beSilent || gn->type & OP_SILENT; 335 } 336 337 /* See if the given target is precious. */ 338 Boolean 339 Targ_Precious(const GNode *gn) 340 { 341 /* XXX: Why are '::' targets precious? */ 342 return allPrecious || gn->type & (OP_PRECIOUS | OP_DOUBLEDEP); 343 } 344 345 /* 346 * The main target to be made; only for debugging output. 347 * See mainNode in parse.c for the definitive source. 348 */ 349 static GNode *mainTarg; 350 351 /* Remember the main target to make; only used for debugging. */ 352 void 353 Targ_SetMain(GNode *gn) 354 { 355 mainTarg = gn; 356 } 357 358 static void 359 PrintNodeNames(GNodeList *gnodes) 360 { 361 GNodeListNode *node; 362 363 for (node = gnodes->first; node != NULL; node = node->next) { 364 GNode *gn = node->datum; 365 debug_printf(" %s%s", gn->name, gn->cohort_num); 366 } 367 } 368 369 static void 370 PrintNodeNamesLine(const char *label, GNodeList *gnodes) 371 { 372 if (Lst_IsEmpty(gnodes)) 373 return; 374 debug_printf("# %s:", label); 375 PrintNodeNames(gnodes); 376 debug_printf("\n"); 377 } 378 379 void 380 Targ_PrintCmds(GNode *gn) 381 { 382 StringListNode *ln; 383 for (ln = gn->commands->first; ln != NULL; ln = ln->next) { 384 const char *cmd = ln->datum; 385 debug_printf("\t%s\n", cmd); 386 } 387 } 388 389 /* Format a modification time in some reasonable way and return it. 390 * The time is placed in a static area, so it is overwritten with each call. */ 391 char * 392 Targ_FmtTime(time_t tm) 393 { 394 struct tm *parts; 395 static char buf[128]; 396 397 parts = localtime(&tm); 398 (void)strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts); 399 return buf; 400 } 401 402 /* Print out a type field giving only those attributes the user can set. */ 403 void 404 Targ_PrintType(int type) 405 { 406 int tbit; 407 408 #define PRINTBIT(attr) case CONCAT(OP_,attr): debug_printf(" ." #attr); break 409 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG))debug_printf(" ." #attr); break 410 411 type &= ~OP_OPMASK; 412 413 while (type) { 414 tbit = 1 << (ffs(type) - 1); 415 type &= ~tbit; 416 417 switch(tbit) { 418 PRINTBIT(OPTIONAL); 419 PRINTBIT(USE); 420 PRINTBIT(EXEC); 421 PRINTBIT(IGNORE); 422 PRINTBIT(PRECIOUS); 423 PRINTBIT(SILENT); 424 PRINTBIT(MAKE); 425 PRINTBIT(JOIN); 426 PRINTBIT(INVISIBLE); 427 PRINTBIT(NOTMAIN); 428 PRINTDBIT(LIB); 429 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */ 430 case OP_MEMBER: if (DEBUG(TARG))debug_printf(" .MEMBER"); break; 431 PRINTDBIT(ARCHV); 432 PRINTDBIT(MADE); 433 PRINTDBIT(PHONY); 434 } 435 } 436 } 437 438 static const char * 439 made_name(GNodeMade made) 440 { 441 switch (made) { 442 case UNMADE: return "unmade"; 443 case DEFERRED: return "deferred"; 444 case REQUESTED: return "requested"; 445 case BEINGMADE: return "being made"; 446 case MADE: return "made"; 447 case UPTODATE: return "up-to-date"; 448 case ERROR: return "error when made"; 449 case ABORTED: return "aborted"; 450 default: return "unknown enum_made value"; 451 } 452 } 453 454 static const char * 455 GNode_OpName(const GNode *gn) 456 { 457 switch (gn->type & OP_OPMASK) { 458 case OP_DEPENDS: 459 return ":"; 460 case OP_FORCE: 461 return "!"; 462 case OP_DOUBLEDEP: 463 return "::"; 464 } 465 return ""; 466 } 467 468 /* Print the contents of a node. */ 469 void 470 Targ_PrintNode(GNode *gn, int pass) 471 { 472 debug_printf("# %s%s", gn->name, gn->cohort_num); 473 GNode_FprintDetails(opts.debug_file, ", ", gn, "\n"); 474 if (gn->flags == 0) 475 return; 476 477 if (GNode_IsTarget(gn)) { 478 debug_printf("#\n"); 479 if (gn == mainTarg) { 480 debug_printf("# *** MAIN TARGET ***\n"); 481 } 482 if (pass >= 2) { 483 if (gn->unmade > 0) { 484 debug_printf("# %d unmade children\n", gn->unmade); 485 } else { 486 debug_printf("# No unmade children\n"); 487 } 488 if (!(gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC))) { 489 if (gn->mtime != 0) { 490 debug_printf("# last modified %s: %s\n", 491 Targ_FmtTime(gn->mtime), 492 made_name(gn->made)); 493 } else if (gn->made != UNMADE) { 494 debug_printf("# non-existent (maybe): %s\n", 495 made_name(gn->made)); 496 } else { 497 debug_printf("# unmade\n"); 498 } 499 } 500 PrintNodeNamesLine("implicit parents", gn->implicitParents); 501 } else { 502 if (gn->unmade) 503 debug_printf("# %d unmade children\n", gn->unmade); 504 } 505 PrintNodeNamesLine("parents", gn->parents); 506 PrintNodeNamesLine("order_pred", gn->order_pred); 507 PrintNodeNamesLine("order_succ", gn->order_succ); 508 509 debug_printf("%-16s%s", gn->name, GNode_OpName(gn)); 510 Targ_PrintType(gn->type); 511 PrintNodeNames(gn->children); 512 debug_printf("\n"); 513 Targ_PrintCmds(gn); 514 debug_printf("\n\n"); 515 if (gn->type & OP_DOUBLEDEP) { 516 Targ_PrintNodes(gn->cohorts, pass); 517 } 518 } 519 } 520 521 void 522 Targ_PrintNodes(GNodeList *gnodes, int pass) 523 { 524 GNodeListNode *ln; 525 for (ln = gnodes->first; ln != NULL; ln = ln->next) 526 Targ_PrintNode(ln->datum, pass); 527 } 528 529 /* Print only those targets that are just a source. */ 530 static void 531 PrintOnlySources(void) 532 { 533 GNodeListNode *ln; 534 535 for (ln = allTargets->first; ln != NULL; ln = ln->next) { 536 GNode *gn = ln->datum; 537 if (GNode_IsTarget(gn)) 538 continue; 539 540 debug_printf("#\t%s [%s]", gn->name, GNode_Path(gn)); 541 Targ_PrintType(gn->type); 542 debug_printf("\n"); 543 } 544 } 545 546 /* Input: 547 * pass 1 => before processing 548 * 2 => after processing 549 * 3 => after processing, an error occurred 550 */ 551 void 552 Targ_PrintGraph(int pass) 553 { 554 debug_printf("#*** Input graph:\n"); 555 Targ_PrintNodes(allTargets, pass); 556 debug_printf("\n"); 557 debug_printf("\n"); 558 559 debug_printf("#\n"); 560 debug_printf("# Files that are only sources:\n"); 561 PrintOnlySources(); 562 563 debug_printf("#*** Global Variables:\n"); 564 Var_Dump(VAR_GLOBAL); 565 566 debug_printf("#*** Command-line Variables:\n"); 567 Var_Dump(VAR_CMDLINE); 568 569 debug_printf("\n"); 570 Dir_PrintDirectories(); 571 debug_printf("\n"); 572 573 Suff_PrintAll(); 574 } 575 576 /* Propagate some type information to cohort nodes (those from the '::' 577 * dependency operator). 578 * 579 * Should be called after the makefiles are parsed but before any action is 580 * taken. */ 581 void 582 Targ_Propagate(void) 583 { 584 GNodeListNode *ln, *cln; 585 586 for (ln = allTargets->first; ln != NULL; ln = ln->next) { 587 GNode *gn = ln->datum; 588 GNodeType type = gn->type; 589 590 if (!(type & OP_DOUBLEDEP)) 591 continue; 592 593 for (cln = gn->cohorts->first; cln != NULL; cln = cln->next) { 594 GNode *cohort = cln->datum; 595 596 cohort->type |= type & ~OP_OPMASK; 597 } 598 } 599 } 600