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