targ.c revision 168893
1141104Sharti/*- 21590Srgrimes * Copyright (c) 1988, 1989, 1990, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * Copyright (c) 1989 by Berkeley Softworks 51590Srgrimes * All rights reserved. 61590Srgrimes * 71590Srgrimes * This code is derived from software contributed to Berkeley by 81590Srgrimes * Adam de Boor. 91590Srgrimes * 101590Srgrimes * Redistribution and use in source and binary forms, with or without 111590Srgrimes * modification, are permitted provided that the following conditions 121590Srgrimes * are met: 131590Srgrimes * 1. Redistributions of source code must retain the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer. 151590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161590Srgrimes * notice, this list of conditions and the following disclaimer in the 171590Srgrimes * documentation and/or other materials provided with the distribution. 181590Srgrimes * 3. All advertising materials mentioning features or use of this software 191590Srgrimes * must display the following acknowledgement: 201590Srgrimes * This product includes software developed by the University of 211590Srgrimes * California, Berkeley and its contributors. 221590Srgrimes * 4. Neither the name of the University nor the names of its contributors 231590Srgrimes * may be used to endorse or promote products derived from this software 241590Srgrimes * without specific prior written permission. 251590Srgrimes * 261590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 271590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 281590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 291590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 301590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 311590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 321590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 331590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 341590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 351590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 361590Srgrimes * SUCH DAMAGE. 3762833Swsanchez * 3862833Swsanchez * @(#)targ.c 8.2 (Berkeley) 3/19/94 391590Srgrimes */ 401590Srgrimes 4162833Swsanchez#include <sys/cdefs.h> 4294587Sobrien__FBSDID("$FreeBSD: head/usr.bin/make/targ.c 168893 2007-04-20 06:33:25Z fjoe $"); 431590Srgrimes 44144469Sharti/* 45144469Sharti * Functions for maintaining the Lst allTargets. Target nodes are 461590Srgrimes * kept in two structures: a Lst, maintained by the list library, and a 471590Srgrimes * hash table, maintained by the hash library. 481590Srgrimes * 491590Srgrimes * Interface: 50144469Sharti * Targ_Init Initialization procedure. 511590Srgrimes * 52144469Sharti * Targ_NewGN Create a new GNode for the passed target (string). 53144469Sharti * The node is *not* placed in the hash table, though all 54144469Sharti * its fields are initialized. 551590Srgrimes * 56144469Sharti * Targ_FindNode Find the node for a given target, creating and storing 57144469Sharti * it if it doesn't exist and the flags are right 58144469Sharti * (TARG_CREATE) 591590Srgrimes * 60144469Sharti * Targ_FindList Given a list of names, find nodes for all of them. If a 61144469Sharti * name doesn't exist and the TARG_NOCREATE flag was given, 62144469Sharti * an error message is printed. Else, if a name doesn't 63144469Sharti * exist, its node is created. 641590Srgrimes * 65144469Sharti * Targ_Ignore Return TRUE if errors should be ignored when creating 66144469Sharti * the given target. 671590Srgrimes * 68144469Sharti * Targ_Silent Return TRUE if we should be silent when creating the 69144469Sharti * given target. 701590Srgrimes * 71144469Sharti * Targ_Precious Return TRUE if the target is precious and should not 72144469Sharti * be removed if we are interrupted. 731590Srgrimes * 741590Srgrimes * Debugging: 75144469Sharti * Targ_PrintGraph Print out the entire graphm all variables and statistics 76144469Sharti * for the directory cache. Should print something for 77144469Sharti * suffixes, too, but... 781590Srgrimes */ 791590Srgrimes 80141104Sharti#include <stdio.h> 81141104Sharti#include <string.h> 821590Srgrimes 83141104Sharti#include "dir.h" 84141104Sharti#include "globals.h" 85141104Sharti#include "GNode.h" 86141104Sharti#include "hash.h" 87141104Sharti#include "make.h" 88141104Sharti#include "suff.h" 89141104Sharti#include "targ.h" 90141104Sharti#include "util.h" 91141104Sharti#include "var.h" 92141104Sharti 93138916Sharti/* the list of all targets found so far */ 94138916Shartistatic Lst allTargets = Lst_Initializer(allTargets); 95138916Sharti 961590Srgrimesstatic Hash_Table targets; /* a hash table of same */ 971590Srgrimes 98103503Sjmallett#define HTSIZE 191 /* initial size of hash table */ 991590Srgrimes 100144469Sharti/** 101144469Sharti * Targ_Init 1021590Srgrimes * Initialize this module 1031590Srgrimes * 1041590Srgrimes * Side Effects: 1051590Srgrimes * The allTargets list and the targets hash table are initialized 1061590Srgrimes */ 1071590Srgrimesvoid 108138232ShartiTarg_Init(void) 1091590Srgrimes{ 110138232Sharti 111144469Sharti Hash_InitTable(&targets, HTSIZE); 1121590Srgrimes} 1131590Srgrimes 114144469Sharti/** 115144469Sharti * Targ_NewGN 1161590Srgrimes * Create and initialize a new graph node 1171590Srgrimes * 1181590Srgrimes * Results: 1191590Srgrimes * An initialized graph node with the name field filled with a copy 1201590Srgrimes * of the passed name 1211590Srgrimes * 1221590Srgrimes * Side Effects: 1235814Sjkh * The gnode is added to the list of all gnodes. 1241590Srgrimes */ 1251590SrgrimesGNode * 126141252ShartiTarg_NewGN(const char *name) 1271590Srgrimes{ 128144469Sharti GNode *gn; 1291590Srgrimes 130144469Sharti gn = emalloc(sizeof(GNode)); 131144469Sharti gn->name = estrdup(name); 132144469Sharti gn->path = NULL; 133144469Sharti if (name[0] == '-' && name[1] == 'l') { 134144469Sharti gn->type = OP_LIB; 135144469Sharti } else { 136144469Sharti gn->type = 0; 137144469Sharti } 138144469Sharti gn->unmade = 0; 139144469Sharti gn->make = FALSE; 140144469Sharti gn->made = UNMADE; 141144469Sharti gn->childMade = FALSE; 142144469Sharti gn->order = 0; 143144469Sharti gn->mtime = gn->cmtime = 0; 144168893Sfjoe gn->cmtime_gn = NULL; 145144469Sharti Lst_Init(&gn->iParents); 146144469Sharti Lst_Init(&gn->cohorts); 147144469Sharti Lst_Init(&gn->parents); 148144469Sharti Lst_Init(&gn->children); 149144469Sharti Lst_Init(&gn->successors); 150144469Sharti Lst_Init(&gn->preds); 151144469Sharti Lst_Init(&gn->context); 152144469Sharti Lst_Init(&gn->commands); 153144469Sharti gn->suffix = NULL; 1541590Srgrimes 155144469Sharti return (gn); 1561590Srgrimes} 1571590Srgrimes 158144469Sharti/** 159144469Sharti * Targ_FindNode 1601590Srgrimes * Find a node in the list using the given name for matching 1611590Srgrimes * 1621590Srgrimes * Results: 16369527Swill * The node in the list if it was. If it wasn't, return NULL of 1641590Srgrimes * flags was TARG_NOCREATE or the newly created and initialized node 1651590Srgrimes * if it was TARG_CREATE 1661590Srgrimes * 1671590Srgrimes * Side Effects: 1681590Srgrimes * Sometimes a node is created and added to the list 1691590Srgrimes */ 1701590SrgrimesGNode * 171141252ShartiTarg_FindNode(const char *name, int flags) 1721590Srgrimes{ 173144469Sharti GNode *gn; /* node in that element */ 174144469Sharti Hash_Entry *he; /* New or used hash entry for node */ 175144469Sharti Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */ 176144469Sharti /* an entry for the node */ 1771590Srgrimes 178144469Sharti if (flags & TARG_CREATE) { 179144469Sharti he = Hash_CreateEntry(&targets, name, &isNew); 180144469Sharti if (isNew) { 181144469Sharti gn = Targ_NewGN(name); 182144469Sharti Hash_SetValue(he, gn); 183144469Sharti Lst_AtEnd(&allTargets, gn); 184144469Sharti } 185144469Sharti } else { 186144469Sharti he = Hash_FindEntry(&targets, name); 1871590Srgrimes } 1881590Srgrimes 189144469Sharti if (he == NULL) { 190144469Sharti return (NULL); 191144469Sharti } else { 192144469Sharti return (Hash_GetValue(he)); 193144469Sharti } 1941590Srgrimes} 1951590Srgrimes 196144469Sharti/** 197144469Sharti * Targ_FindList 1988874Srgrimes * Make a complete list of GNodes from the given list of names 1991590Srgrimes * 2001590Srgrimes * Results: 2011590Srgrimes * A complete list of graph nodes corresponding to all instances of all 2028874Srgrimes * the names in names. 2031590Srgrimes * 2041590Srgrimes * Side Effects: 2051590Srgrimes * If flags is TARG_CREATE, nodes will be created for all names in 2061590Srgrimes * names which do not yet have graph nodes. If flags is TARG_NOCREATE, 2071590Srgrimes * an error message will be printed for each name which can't be found. 2081590Srgrimes */ 209138916Shartivoid 210138916ShartiTarg_FindList(Lst *nodes, Lst *names, int flags) 2111590Srgrimes{ 212144469Sharti LstNode *ln; /* name list element */ 213144469Sharti GNode *gn; /* node in tLn */ 214144469Sharti char *name; 2151590Srgrimes 216144469Sharti for (ln = Lst_First(names); ln != NULL; ln = Lst_Succ(ln)) { 217144469Sharti name = Lst_Datum(ln); 218144469Sharti gn = Targ_FindNode(name, flags); 219144469Sharti if (gn != NULL) { 220144469Sharti /* 221144469Sharti * Note: Lst_AtEnd must come before the Lst_Concat so 222144469Sharti * the nodes are added to the list in the order in which 223144469Sharti * they were encountered in the makefile. 224144469Sharti */ 225144469Sharti Lst_AtEnd(nodes, gn); 226144469Sharti if (gn->type & OP_DOUBLEDEP) { 227144469Sharti Lst_Concat(nodes, &gn->cohorts, LST_CONCNEW); 228144469Sharti } 229144469Sharti 230144469Sharti } else if (flags == TARG_NOCREATE) { 231144469Sharti Error("\"%s\" -- target unknown.", name); 232144469Sharti } 2331590Srgrimes } 2341590Srgrimes} 2351590Srgrimes 236144469Sharti/** 237144469Sharti * Targ_Ignore 2381590Srgrimes * Return true if should ignore errors when creating gn 2391590Srgrimes * 2401590Srgrimes * Results: 2411590Srgrimes * TRUE if should ignore errors 2421590Srgrimes */ 2431590SrgrimesBoolean 244138232ShartiTarg_Ignore(GNode *gn) 2451590Srgrimes{ 246138232Sharti 247144469Sharti if (ignoreErrors || (gn->type & OP_IGNORE)) { 248144469Sharti return (TRUE); 249144469Sharti } else { 250144469Sharti return (FALSE); 251144469Sharti } 2521590Srgrimes} 2531590Srgrimes 254144469Sharti/** 255144469Sharti * Targ_Silent 2561590Srgrimes * Return true if be silent when creating gn 2571590Srgrimes * 2581590Srgrimes * Results: 2591590Srgrimes * TRUE if should be silent 2601590Srgrimes */ 2611590SrgrimesBoolean 262138232ShartiTarg_Silent(GNode *gn) 2631590Srgrimes{ 264138232Sharti 265144469Sharti if (beSilent || (gn->type & OP_SILENT)) { 266144469Sharti return (TRUE); 267144469Sharti } else { 268144469Sharti return (FALSE); 269144469Sharti } 2701590Srgrimes} 2711590Srgrimes 272144469Sharti/** 273144469Sharti * Targ_Precious 2741590Srgrimes * See if the given target is precious 2751590Srgrimes * 2761590Srgrimes * Results: 2771590Srgrimes * TRUE if it is precious. FALSE otherwise 2781590Srgrimes */ 2791590SrgrimesBoolean 280138232ShartiTarg_Precious(GNode *gn) 2811590Srgrimes{ 282138232Sharti 283144469Sharti if (allPrecious || (gn->type & (OP_PRECIOUS | OP_DOUBLEDEP))) { 284144469Sharti return (TRUE); 285144469Sharti } else { 286144469Sharti return (FALSE); 287144469Sharti } 2881590Srgrimes} 2891590Srgrimes 290144469Shartistatic GNode *mainTarg; /* the main target, as set by Targ_SetMain */ 2911590Srgrimes 292144469Sharti/** 293144469Sharti * Targ_SetMain 2941590Srgrimes * Set our idea of the main target we'll be creating. Used for 2951590Srgrimes * debugging output. 2961590Srgrimes * 2971590Srgrimes * Side Effects: 2981590Srgrimes * "mainTarg" is set to the main target's node. 2991590Srgrimes */ 3001590Srgrimesvoid 301138232ShartiTarg_SetMain(GNode *gn) 3021590Srgrimes{ 303138232Sharti 304144469Sharti mainTarg = gn; 3051590Srgrimes} 3061590Srgrimes 307144469Sharti/** 308144469Sharti * Targ_FmtTime 3091590Srgrimes * Format a modification time in some reasonable way and return it. 3101590Srgrimes * 3111590Srgrimes * Results: 3121590Srgrimes * The time reformatted. 3131590Srgrimes * 3141590Srgrimes * Side Effects: 3151590Srgrimes * The time is placed in a static area, so it is overwritten 3161590Srgrimes * with each call. 3171590Srgrimes */ 3181590Srgrimeschar * 319138232ShartiTarg_FmtTime(time_t modtime) 3201590Srgrimes{ 321144469Sharti struct tm *parts; 322144469Sharti static char buf[128]; 3231590Srgrimes 324144469Sharti parts = localtime(&modtime); 3251590Srgrimes 326144469Sharti strftime(buf, sizeof(buf), "%H:%M:%S %b %d, %Y", parts); 327144469Sharti buf[sizeof(buf) - 1] = '\0'; 328144469Sharti return (buf); 3291590Srgrimes} 3308874Srgrimes 331144469Sharti/** 332144469Sharti * Targ_PrintType 3331590Srgrimes * Print out a type field giving only those attributes the user can 3341590Srgrimes * set. 3351590Srgrimes */ 3361590Srgrimesvoid 337138232ShartiTarg_PrintType(int type) 3381590Srgrimes{ 339146184Sharti static const struct flag2str type2str[] = { 340146184Sharti { OP_OPTIONAL, ".OPTIONAL" }, 341146184Sharti { OP_USE, ".USE" }, 342146184Sharti { OP_EXEC, ".EXEC" }, 343146184Sharti { OP_IGNORE, ".IGNORE" }, 344146184Sharti { OP_PRECIOUS, ".PRECIOUS" }, 345146184Sharti { OP_SILENT, ".SILENT" }, 346146184Sharti { OP_MAKE, ".MAKE" }, 347146184Sharti { OP_JOIN, ".JOIN" }, 348146184Sharti { OP_INVISIBLE, ".INVISIBLE" }, 349146184Sharti { OP_NOTMAIN, ".NOTMAIN" }, 350146184Sharti { OP_PHONY, ".PHONY" }, 351146184Sharti { OP_LIB, ".LIB" }, 352146184Sharti { OP_MEMBER, ".MEMBER" }, 353146184Sharti { OP_ARCHV, ".ARCHV" }, 354146184Sharti { 0, NULL } 355146184Sharti }; 3568874Srgrimes 357144469Sharti type &= ~OP_OPMASK; 358146184Sharti if (!DEBUG(TARG)) 359146184Sharti type &= ~(OP_ARCHV | OP_LIB | OP_MEMBER); 360146184Sharti print_flags(stdout, type2str, type, 0); 3611590Srgrimes} 3621590Srgrimes 363144469Sharti/** 364144469Sharti * TargPrintNode 3651590Srgrimes * print the contents of a node 3661590Srgrimes */ 3671590Srgrimesstatic int 368143650ShartiTargPrintNode(const GNode *gn, int pass) 3691590Srgrimes{ 370144469Sharti const LstNode *tln; 371138232Sharti 372144469Sharti if (!OP_NOP(gn->type)) { 373144469Sharti printf("#\n"); 374144469Sharti if (gn == mainTarg) { 375144469Sharti printf("# *** MAIN TARGET ***\n"); 3761590Srgrimes } 377144469Sharti if (pass == 2) { 378144469Sharti if (gn->unmade) { 379144469Sharti printf("# %d unmade children\n", gn->unmade); 380144469Sharti } else { 381144469Sharti printf("# No unmade children\n"); 382144469Sharti } 383144469Sharti if (!(gn->type & (OP_JOIN | OP_USE | OP_EXEC))) { 384144469Sharti if (gn->mtime != 0) { 385144469Sharti printf("# last modified %s: %s\n", 386144469Sharti Targ_FmtTime(gn->mtime), 387144469Sharti gn->made == UNMADE ? "unmade" : 388144469Sharti gn->made == MADE ? "made" : 389144469Sharti gn->made == UPTODATE ? "up-to-date": 390144469Sharti "error when made"); 391144469Sharti } else if (gn->made != UNMADE) { 392144469Sharti printf("# non-existent (maybe): %s\n", 393144469Sharti gn->made == MADE ? "made" : 394144469Sharti gn->made == UPTODATE ? "up-to-date": 395144469Sharti gn->made == ERROR?"error when made": 396144469Sharti "aborted"); 397144469Sharti } else { 398144469Sharti printf("# unmade\n"); 399144469Sharti } 400144469Sharti } 401144469Sharti if (!Lst_IsEmpty(&gn->iParents)) { 402144469Sharti printf("# implicit parents: "); 403144469Sharti LST_FOREACH(tln, &gn->iParents) 404144469Sharti printf("%s ", ((const GNode *) 405144469Sharti Lst_Datum(tln))->name); 406144469Sharti printf("\n"); 407144469Sharti } 408144469Sharti } 409144469Sharti if (!Lst_IsEmpty(&gn->parents)) { 410144469Sharti printf("# parents: "); 411144469Sharti LST_FOREACH(tln, &gn->parents) 412144469Sharti printf("%s ", ((const GNode *) 413144469Sharti Lst_Datum(tln))->name); 414144469Sharti printf("\n"); 415144469Sharti } 416144469Sharti 417144469Sharti printf("%-16s", gn->name); 418144469Sharti switch (gn->type & OP_OPMASK) { 419144469Sharti case OP_DEPENDS: 420144469Sharti printf(": "); 421144469Sharti break; 422144469Sharti case OP_FORCE: 423144469Sharti printf("! "); 424144469Sharti break; 425144469Sharti case OP_DOUBLEDEP: 426144469Sharti printf(":: "); 427144469Sharti break; 428144469Sharti default: 429144469Sharti break; 430144469Sharti } 431144469Sharti Targ_PrintType(gn->type); 432144469Sharti LST_FOREACH(tln, &gn->children) 433143650Sharti printf("%s ", ((const GNode *)Lst_Datum(tln))->name); 434143650Sharti printf("\n"); 435144469Sharti LST_FOREACH(tln, &gn->commands) 436144469Sharti printf("\t%s\n", (const char *)Lst_Datum(tln)); 437144469Sharti printf("\n\n"); 438144469Sharti if (gn->type & OP_DOUBLEDEP) { 439144469Sharti LST_FOREACH(tln, &gn->cohorts) 440144469Sharti TargPrintNode((const GNode *)Lst_Datum(tln), 441144469Sharti pass); 442144469Sharti } 4431590Srgrimes } 444144469Sharti return (0); 4451590Srgrimes} 4461590Srgrimes 447144469Sharti/** 448144469Sharti * Targ_PrintGraph 449104696Sjmallett * Print the entire graph. 4501590Srgrimes */ 4511590Srgrimesvoid 452138232ShartiTarg_PrintGraph(int pass) 4531590Srgrimes{ 454144469Sharti const GNode *gn; 455144469Sharti const LstNode *tln; 456138264Sharti 457144469Sharti printf("#*** Input graph:\n"); 458144469Sharti LST_FOREACH(tln, &allTargets) 459144469Sharti TargPrintNode((const GNode *)Lst_Datum(tln), pass); 460144469Sharti printf("\n\n"); 461143650Sharti 462144469Sharti printf("#\n# Files that are only sources:\n"); 463144469Sharti LST_FOREACH(tln, &allTargets) { 464144469Sharti gn = Lst_Datum(tln); 465144469Sharti if (OP_NOP(gn->type)) 466144469Sharti printf("#\t%s [%s]\n", gn->name, 467144469Sharti gn->path ? gn->path : gn->name); 468144469Sharti } 469146039Sharti Var_Dump(); 470144469Sharti printf("\n"); 471144469Sharti Dir_PrintDirectories(); 472144469Sharti printf("\n"); 473144469Sharti Suff_PrintAll(); 4741590Srgrimes} 475