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$"); 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> 811590Srgrimes 82141104Sharti#include "dir.h" 83141104Sharti#include "globals.h" 84141104Sharti#include "GNode.h" 85141104Sharti#include "hash.h" 86141104Sharti#include "suff.h" 87141104Sharti#include "targ.h" 88141104Sharti#include "util.h" 89141104Sharti#include "var.h" 90141104Sharti 91138916Sharti/* the list of all targets found so far */ 92138916Shartistatic Lst allTargets = Lst_Initializer(allTargets); 93138916Sharti 941590Srgrimesstatic Hash_Table targets; /* a hash table of same */ 951590Srgrimes 96103503Sjmallett#define HTSIZE 191 /* initial size of hash table */ 971590Srgrimes 98144469Sharti/** 99144469Sharti * Targ_Init 1001590Srgrimes * Initialize this module 1011590Srgrimes * 1021590Srgrimes * Side Effects: 1031590Srgrimes * The allTargets list and the targets hash table are initialized 1041590Srgrimes */ 1051590Srgrimesvoid 106138232ShartiTarg_Init(void) 1071590Srgrimes{ 108138232Sharti 109144469Sharti Hash_InitTable(&targets, HTSIZE); 1101590Srgrimes} 1111590Srgrimes 112144469Sharti/** 113144469Sharti * Targ_NewGN 1141590Srgrimes * Create and initialize a new graph node 1151590Srgrimes * 1161590Srgrimes * Results: 1171590Srgrimes * An initialized graph node with the name field filled with a copy 1181590Srgrimes * of the passed name 1191590Srgrimes * 1201590Srgrimes * Side Effects: 1215814Sjkh * The gnode is added to the list of all gnodes. 1221590Srgrimes */ 1231590SrgrimesGNode * 124141252ShartiTarg_NewGN(const char *name) 1251590Srgrimes{ 126144469Sharti GNode *gn; 1271590Srgrimes 128144469Sharti gn = emalloc(sizeof(GNode)); 129144469Sharti gn->name = estrdup(name); 130144469Sharti gn->path = NULL; 131144469Sharti if (name[0] == '-' && name[1] == 'l') { 132144469Sharti gn->type = OP_LIB; 133144469Sharti } else { 134144469Sharti gn->type = 0; 135144469Sharti } 136144469Sharti gn->unmade = 0; 137144469Sharti gn->make = FALSE; 138144469Sharti gn->made = UNMADE; 139144469Sharti gn->childMade = FALSE; 140144469Sharti gn->order = 0; 141144469Sharti gn->mtime = gn->cmtime = 0; 142168893Sfjoe gn->cmtime_gn = NULL; 143144469Sharti Lst_Init(&gn->iParents); 144144469Sharti Lst_Init(&gn->cohorts); 145144469Sharti Lst_Init(&gn->parents); 146144469Sharti Lst_Init(&gn->children); 147144469Sharti Lst_Init(&gn->successors); 148144469Sharti Lst_Init(&gn->preds); 149144469Sharti Lst_Init(&gn->context); 150144469Sharti Lst_Init(&gn->commands); 151144469Sharti gn->suffix = NULL; 1521590Srgrimes 153144469Sharti return (gn); 1541590Srgrimes} 1551590Srgrimes 156144469Sharti/** 157144469Sharti * Targ_FindNode 1581590Srgrimes * Find a node in the list using the given name for matching 1591590Srgrimes * 1601590Srgrimes * Results: 16169527Swill * The node in the list if it was. If it wasn't, return NULL of 1621590Srgrimes * flags was TARG_NOCREATE or the newly created and initialized node 1631590Srgrimes * if it was TARG_CREATE 1641590Srgrimes * 1651590Srgrimes * Side Effects: 1661590Srgrimes * Sometimes a node is created and added to the list 1671590Srgrimes */ 1681590SrgrimesGNode * 169141252ShartiTarg_FindNode(const char *name, int flags) 1701590Srgrimes{ 171144469Sharti GNode *gn; /* node in that element */ 172144469Sharti Hash_Entry *he; /* New or used hash entry for node */ 173144469Sharti Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */ 174144469Sharti /* an entry for the node */ 1751590Srgrimes 176144469Sharti if (flags & TARG_CREATE) { 177144469Sharti he = Hash_CreateEntry(&targets, name, &isNew); 178144469Sharti if (isNew) { 179144469Sharti gn = Targ_NewGN(name); 180144469Sharti Hash_SetValue(he, gn); 181144469Sharti Lst_AtEnd(&allTargets, gn); 182144469Sharti } 183144469Sharti } else { 184144469Sharti he = Hash_FindEntry(&targets, name); 1851590Srgrimes } 1861590Srgrimes 187144469Sharti if (he == NULL) { 188144469Sharti return (NULL); 189144469Sharti } else { 190144469Sharti return (Hash_GetValue(he)); 191144469Sharti } 1921590Srgrimes} 1931590Srgrimes 194144469Sharti/** 195144469Sharti * Targ_FindList 1968874Srgrimes * Make a complete list of GNodes from the given list of names 1971590Srgrimes * 1981590Srgrimes * Results: 1991590Srgrimes * A complete list of graph nodes corresponding to all instances of all 2008874Srgrimes * the names in names. 2011590Srgrimes * 2021590Srgrimes * Side Effects: 2031590Srgrimes * If flags is TARG_CREATE, nodes will be created for all names in 2041590Srgrimes * names which do not yet have graph nodes. If flags is TARG_NOCREATE, 2051590Srgrimes * an error message will be printed for each name which can't be found. 2061590Srgrimes */ 207138916Shartivoid 208138916ShartiTarg_FindList(Lst *nodes, Lst *names, int flags) 2091590Srgrimes{ 210144469Sharti LstNode *ln; /* name list element */ 211144469Sharti GNode *gn; /* node in tLn */ 212144469Sharti char *name; 2131590Srgrimes 214144469Sharti for (ln = Lst_First(names); ln != NULL; ln = Lst_Succ(ln)) { 215144469Sharti name = Lst_Datum(ln); 216144469Sharti gn = Targ_FindNode(name, flags); 217144469Sharti if (gn != NULL) { 218144469Sharti /* 219144469Sharti * Note: Lst_AtEnd must come before the Lst_Concat so 220144469Sharti * the nodes are added to the list in the order in which 221144469Sharti * they were encountered in the makefile. 222144469Sharti */ 223144469Sharti Lst_AtEnd(nodes, gn); 224144469Sharti if (gn->type & OP_DOUBLEDEP) { 225144469Sharti Lst_Concat(nodes, &gn->cohorts, LST_CONCNEW); 226144469Sharti } 227144469Sharti 228144469Sharti } else if (flags == TARG_NOCREATE) { 229144469Sharti Error("\"%s\" -- target unknown.", name); 230144469Sharti } 2311590Srgrimes } 2321590Srgrimes} 2331590Srgrimes 234144469Sharti/** 235144469Sharti * Targ_Ignore 2361590Srgrimes * Return true if should ignore errors when creating gn 2371590Srgrimes * 2381590Srgrimes * Results: 2391590Srgrimes * TRUE if should ignore errors 2401590Srgrimes */ 2411590SrgrimesBoolean 242138232ShartiTarg_Ignore(GNode *gn) 2431590Srgrimes{ 244138232Sharti 245144469Sharti if (ignoreErrors || (gn->type & OP_IGNORE)) { 246144469Sharti return (TRUE); 247144469Sharti } else { 248144469Sharti return (FALSE); 249144469Sharti } 2501590Srgrimes} 2511590Srgrimes 252144469Sharti/** 253144469Sharti * Targ_Silent 2541590Srgrimes * Return true if be silent when creating gn 2551590Srgrimes * 2561590Srgrimes * Results: 2571590Srgrimes * TRUE if should be silent 2581590Srgrimes */ 2591590SrgrimesBoolean 260138232ShartiTarg_Silent(GNode *gn) 2611590Srgrimes{ 262138232Sharti 263144469Sharti if (beSilent || (gn->type & OP_SILENT)) { 264144469Sharti return (TRUE); 265144469Sharti } else { 266144469Sharti return (FALSE); 267144469Sharti } 2681590Srgrimes} 2691590Srgrimes 270144469Sharti/** 271144469Sharti * Targ_Precious 2721590Srgrimes * See if the given target is precious 2731590Srgrimes * 2741590Srgrimes * Results: 2751590Srgrimes * TRUE if it is precious. FALSE otherwise 2761590Srgrimes */ 2771590SrgrimesBoolean 278138232ShartiTarg_Precious(GNode *gn) 2791590Srgrimes{ 280138232Sharti 281144469Sharti if (allPrecious || (gn->type & (OP_PRECIOUS | OP_DOUBLEDEP))) { 282144469Sharti return (TRUE); 283144469Sharti } else { 284144469Sharti return (FALSE); 285144469Sharti } 2861590Srgrimes} 2871590Srgrimes 288144469Shartistatic GNode *mainTarg; /* the main target, as set by Targ_SetMain */ 2891590Srgrimes 290144469Sharti/** 291144469Sharti * Targ_SetMain 2921590Srgrimes * Set our idea of the main target we'll be creating. Used for 2931590Srgrimes * debugging output. 2941590Srgrimes * 2951590Srgrimes * Side Effects: 2961590Srgrimes * "mainTarg" is set to the main target's node. 2971590Srgrimes */ 2981590Srgrimesvoid 299138232ShartiTarg_SetMain(GNode *gn) 3001590Srgrimes{ 301138232Sharti 302144469Sharti mainTarg = gn; 3031590Srgrimes} 3041590Srgrimes 305144469Sharti/** 306144469Sharti * Targ_FmtTime 3071590Srgrimes * Format a modification time in some reasonable way and return it. 3081590Srgrimes * 3091590Srgrimes * Results: 3101590Srgrimes * The time reformatted. 3111590Srgrimes * 3121590Srgrimes * Side Effects: 3131590Srgrimes * The time is placed in a static area, so it is overwritten 3141590Srgrimes * with each call. 3151590Srgrimes */ 3161590Srgrimeschar * 317138232ShartiTarg_FmtTime(time_t modtime) 3181590Srgrimes{ 319144469Sharti struct tm *parts; 320144469Sharti static char buf[128]; 3211590Srgrimes 322144469Sharti parts = localtime(&modtime); 3231590Srgrimes 324144469Sharti strftime(buf, sizeof(buf), "%H:%M:%S %b %d, %Y", parts); 325144469Sharti buf[sizeof(buf) - 1] = '\0'; 326144469Sharti return (buf); 3271590Srgrimes} 3288874Srgrimes 329144469Sharti/** 330144469Sharti * Targ_PrintType 3311590Srgrimes * Print out a type field giving only those attributes the user can 3321590Srgrimes * set. 3331590Srgrimes */ 3341590Srgrimesvoid 335138232ShartiTarg_PrintType(int type) 3361590Srgrimes{ 337146184Sharti static const struct flag2str type2str[] = { 338146184Sharti { OP_OPTIONAL, ".OPTIONAL" }, 339146184Sharti { OP_USE, ".USE" }, 340146184Sharti { OP_EXEC, ".EXEC" }, 341146184Sharti { OP_IGNORE, ".IGNORE" }, 342146184Sharti { OP_PRECIOUS, ".PRECIOUS" }, 343146184Sharti { OP_SILENT, ".SILENT" }, 344146184Sharti { OP_MAKE, ".MAKE" }, 345146184Sharti { OP_JOIN, ".JOIN" }, 346146184Sharti { OP_INVISIBLE, ".INVISIBLE" }, 347146184Sharti { OP_NOTMAIN, ".NOTMAIN" }, 348146184Sharti { OP_PHONY, ".PHONY" }, 349146184Sharti { OP_LIB, ".LIB" }, 350146184Sharti { OP_MEMBER, ".MEMBER" }, 351146184Sharti { OP_ARCHV, ".ARCHV" }, 352146184Sharti { 0, NULL } 353146184Sharti }; 3548874Srgrimes 355144469Sharti type &= ~OP_OPMASK; 356146184Sharti if (!DEBUG(TARG)) 357146184Sharti type &= ~(OP_ARCHV | OP_LIB | OP_MEMBER); 358146184Sharti print_flags(stdout, type2str, type, 0); 3591590Srgrimes} 3601590Srgrimes 361144469Sharti/** 362144469Sharti * TargPrintNode 3631590Srgrimes * print the contents of a node 3641590Srgrimes */ 3651590Srgrimesstatic int 366143650ShartiTargPrintNode(const GNode *gn, int pass) 3671590Srgrimes{ 368144469Sharti const LstNode *tln; 369138232Sharti 370144469Sharti if (!OP_NOP(gn->type)) { 371144469Sharti printf("#\n"); 372144469Sharti if (gn == mainTarg) { 373144469Sharti printf("# *** MAIN TARGET ***\n"); 3741590Srgrimes } 375144469Sharti if (pass == 2) { 376144469Sharti if (gn->unmade) { 377144469Sharti printf("# %d unmade children\n", gn->unmade); 378144469Sharti } else { 379144469Sharti printf("# No unmade children\n"); 380144469Sharti } 381144469Sharti if (!(gn->type & (OP_JOIN | OP_USE | OP_EXEC))) { 382144469Sharti if (gn->mtime != 0) { 383144469Sharti printf("# last modified %s: %s\n", 384144469Sharti Targ_FmtTime(gn->mtime), 385144469Sharti gn->made == UNMADE ? "unmade" : 386144469Sharti gn->made == MADE ? "made" : 387144469Sharti gn->made == UPTODATE ? "up-to-date": 388144469Sharti "error when made"); 389144469Sharti } else if (gn->made != UNMADE) { 390144469Sharti printf("# non-existent (maybe): %s\n", 391144469Sharti gn->made == MADE ? "made" : 392144469Sharti gn->made == UPTODATE ? "up-to-date": 393144469Sharti gn->made == ERROR?"error when made": 394144469Sharti "aborted"); 395144469Sharti } else { 396144469Sharti printf("# unmade\n"); 397144469Sharti } 398144469Sharti } 399144469Sharti if (!Lst_IsEmpty(&gn->iParents)) { 400144469Sharti printf("# implicit parents: "); 401144469Sharti LST_FOREACH(tln, &gn->iParents) 402144469Sharti printf("%s ", ((const GNode *) 403144469Sharti Lst_Datum(tln))->name); 404144469Sharti printf("\n"); 405144469Sharti } 406144469Sharti } 407144469Sharti if (!Lst_IsEmpty(&gn->parents)) { 408144469Sharti printf("# parents: "); 409144469Sharti LST_FOREACH(tln, &gn->parents) 410144469Sharti printf("%s ", ((const GNode *) 411144469Sharti Lst_Datum(tln))->name); 412144469Sharti printf("\n"); 413144469Sharti } 414144469Sharti 415144469Sharti printf("%-16s", gn->name); 416144469Sharti switch (gn->type & OP_OPMASK) { 417144469Sharti case OP_DEPENDS: 418144469Sharti printf(": "); 419144469Sharti break; 420144469Sharti case OP_FORCE: 421144469Sharti printf("! "); 422144469Sharti break; 423144469Sharti case OP_DOUBLEDEP: 424144469Sharti printf(":: "); 425144469Sharti break; 426144469Sharti default: 427144469Sharti break; 428144469Sharti } 429144469Sharti Targ_PrintType(gn->type); 430144469Sharti LST_FOREACH(tln, &gn->children) 431143650Sharti printf("%s ", ((const GNode *)Lst_Datum(tln))->name); 432143650Sharti printf("\n"); 433144469Sharti LST_FOREACH(tln, &gn->commands) 434144469Sharti printf("\t%s\n", (const char *)Lst_Datum(tln)); 435144469Sharti printf("\n\n"); 436144469Sharti if (gn->type & OP_DOUBLEDEP) { 437144469Sharti LST_FOREACH(tln, &gn->cohorts) 438144469Sharti TargPrintNode((const GNode *)Lst_Datum(tln), 439144469Sharti pass); 440144469Sharti } 4411590Srgrimes } 442144469Sharti return (0); 4431590Srgrimes} 4441590Srgrimes 445144469Sharti/** 446144469Sharti * Targ_PrintGraph 447104696Sjmallett * Print the entire graph. 4481590Srgrimes */ 4491590Srgrimesvoid 450138232ShartiTarg_PrintGraph(int pass) 4511590Srgrimes{ 452144469Sharti const GNode *gn; 453144469Sharti const LstNode *tln; 454138264Sharti 455144469Sharti printf("#*** Input graph:\n"); 456144469Sharti LST_FOREACH(tln, &allTargets) 457144469Sharti TargPrintNode((const GNode *)Lst_Datum(tln), pass); 458144469Sharti printf("\n\n"); 459143650Sharti 460144469Sharti printf("#\n# Files that are only sources:\n"); 461144469Sharti LST_FOREACH(tln, &allTargets) { 462144469Sharti gn = Lst_Datum(tln); 463144469Sharti if (OP_NOP(gn->type)) 464144469Sharti printf("#\t%s [%s]\n", gn->name, 465144469Sharti gn->path ? gn->path : gn->name); 466144469Sharti } 467146039Sharti Var_Dump(); 468144469Sharti printf("\n"); 469144469Sharti Dir_PrintDirectories(); 470144469Sharti printf("\n"); 471144469Sharti Suff_PrintAll(); 4721590Srgrimes} 473