home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / make / targ.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-18  |  15.8 KB  |  582 lines

  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. static char sccsid[] = "@(#)targ.c    5.9 (Berkeley) 3/1/91";
  41. #endif /* not lint */
  42.  
  43. /*-
  44.  * targ.c --
  45.  *    Functions for maintaining the Lst allTargets. Target nodes are
  46.  * kept in two structures: a Lst, maintained by the list library, and a
  47.  * hash table, maintained by the hash library.
  48.  *
  49.  * Interface:
  50.  *    Targ_Init             Initialization procedure.
  51.  *
  52.  *    Targ_NewGN            Create a new GNode for the passed target
  53.  *                          (string). The node is *not* placed in the
  54.  *                          hash table, though all its fields are
  55.  *                          initialized.
  56.  *
  57.  *    Targ_FindNode            Find the node for a given target, creating
  58.  *                          and storing it if it doesn't exist and the
  59.  *                          flags are right (TARG_CREATE)
  60.  *
  61.  *    Targ_FindList            Given a list of names, find nodes for all
  62.  *                          of them. If a name doesn't exist and the
  63.  *                          TARG_NOCREATE flag was given, an error message
  64.  *                          is printed. Else, if a name doesn't exist,
  65.  *                          its node is created.
  66.  *
  67.  *    Targ_Ignore            Return TRUE if errors should be ignored when
  68.  *                          creating the given target.
  69.  *
  70.  *    Targ_Silent            Return TRUE if we should be silent when
  71.  *                          creating the given target.
  72.  *
  73.  *    Targ_Precious            Return TRUE if the target is precious and
  74.  *                          should not be removed if we are interrupted.
  75.  *
  76.  * Debugging:
  77.  *    Targ_PrintGraph            Print out the entire graphm all variables
  78.  *                          and statistics for the directory cache. Should
  79.  *                          print something for suffixes, too, but...
  80.  */
  81.  
  82. #include      <stdio.h>
  83. #include      <time.h>
  84. #include      "make.h"
  85. #include      "hash.h"
  86.  
  87. static Lst        allTargets;    /* the list of all targets found so far */
  88. static Hash_Table targets;    /* a hash table of same */
  89.  
  90. #define HTSIZE    191        /* initial size of hash table */
  91.  
  92. /*-
  93.  *-----------------------------------------------------------------------
  94.  * Targ_Init --
  95.  *    Initialize this module
  96.  *
  97.  * Results:
  98.  *    None
  99.  *
  100.  * Side Effects:
  101.  *    The allTargets list and the targets hash table are initialized
  102.  *-----------------------------------------------------------------------
  103.  */
  104. void
  105. Targ_Init ()
  106. {
  107.     allTargets = Lst_Init (FALSE);
  108.     Hash_InitTable (&targets, HTSIZE);
  109. }
  110.  
  111. /*-
  112.  *-----------------------------------------------------------------------
  113.  * Targ_NewGN  --
  114.  *    Create and initialize a new graph node
  115.  *
  116.  * Results:
  117.  *    An initialized graph node with the name field filled with a copy
  118.  *    of the passed name
  119.  *
  120.  * Side Effects:
  121.  *    None.
  122.  *-----------------------------------------------------------------------
  123.  */
  124. GNode *
  125. Targ_NewGN (name)
  126.     char           *name;    /* the name to stick in the new node */
  127. {
  128.     register GNode *gn;
  129.  
  130.     gn = (GNode *) emalloc (sizeof (GNode));
  131.     gn->name = strdup (name);
  132.     gn->path = (char *) 0;
  133.     if (name[0] == '-' && name[1] == 'l') {
  134.     gn->type = OP_LIB;
  135.     } else {
  136.     gn->type = 0;
  137.     }
  138.     gn->unmade =        0;
  139.     gn->make =             FALSE;
  140.     gn->made =             UNMADE;
  141.     gn->childMade =     FALSE;
  142.     gn->mtime = gn->cmtime = 0;
  143.     gn->iParents =      Lst_Init (FALSE);
  144.     gn->cohorts =       Lst_Init (FALSE);
  145.     gn->parents =       Lst_Init (FALSE);
  146.     gn->children =      Lst_Init (FALSE);
  147.     gn->successors =     Lst_Init(FALSE);
  148.     gn->preds =         Lst_Init(FALSE);
  149.     gn->context =       Lst_Init (FALSE);
  150.     gn->commands =      Lst_Init (FALSE);
  151.  
  152.     return (gn);
  153. }
  154.  
  155. /*-
  156.  *-----------------------------------------------------------------------
  157.  * Targ_FindNode  --
  158.  *    Find a node in the list using the given name for matching
  159.  *
  160.  * Results:
  161.  *    The node in the list if it was. If it wasn't, return NILGNODE of
  162.  *    flags was TARG_NOCREATE or the newly created and initialized node
  163.  *    if it was TARG_CREATE
  164.  *
  165.  * Side Effects:
  166.  *    Sometimes a node is created and added to the list
  167.  *-----------------------------------------------------------------------
  168.  */
  169. GNode *
  170. Targ_FindNode (name, flags)
  171.     char           *name;    /* the name to find */
  172.     int             flags;    /* flags governing events when target not
  173.                  * found */
  174. {
  175.     GNode         *gn;          /* node in that element */
  176.     Hash_Entry      *he;          /* New or used hash entry for node */
  177.     Boolean      isNew;      /* Set TRUE if Hash_CreateEntry had to create */
  178.                   /* an entry for the node */
  179.  
  180.  
  181.     if (flags & TARG_CREATE) {
  182.     he = Hash_CreateEntry (&targets, name, &isNew);
  183.     if (isNew) {
  184.         gn = Targ_NewGN (name);
  185.         Hash_SetValue (he, gn);
  186.         (void) Lst_AtEnd (allTargets, (ClientData)gn);
  187.     }
  188.     } else {
  189.     he = Hash_FindEntry (&targets, name);
  190.     }
  191.  
  192.     if (he == (Hash_Entry *) NULL) {
  193.     return (NILGNODE);
  194.     } else {
  195.     return ((GNode *) Hash_GetValue (he));
  196.     }
  197. }
  198.  
  199. /*-
  200.  *-----------------------------------------------------------------------
  201.  * Targ_FindList --
  202.  *    Make a complete list of GNodes from the given list of names 
  203.  *
  204.  * Results:
  205.  *    A complete list of graph nodes corresponding to all instances of all
  206.  *    the names in names. 
  207.  *
  208.  * Side Effects:
  209.  *    If flags is TARG_CREATE, nodes will be created for all names in
  210.  *    names which do not yet have graph nodes. If flags is TARG_NOCREATE,
  211.  *    an error message will be printed for each name which can't be found.
  212.  * -----------------------------------------------------------------------
  213.  */
  214. Lst
  215. Targ_FindList (names, flags)
  216.     Lst               names;    /* list of names to find */
  217.     int            flags;    /* flags used if no node is found for a given
  218.                  * name */
  219. {
  220.     Lst            nodes;    /* result list */
  221.     register LstNode  ln;        /* name list element */
  222.     register GNode *gn;        /* node in tLn */
  223.     char          *name;
  224.  
  225.     nodes = Lst_Init (FALSE);
  226.  
  227.     if (Lst_Open (names) == FAILURE) {
  228.     return (nodes);
  229.     }
  230.     while ((ln = Lst_Next (names)) != NILLNODE) {
  231.     name = (char *)Lst_Datum(ln);
  232.     gn = Targ_FindNode (name, flags);
  233.     if (gn != NILGNODE) {
  234.         /*
  235.          * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
  236.          * are added to the list in the order in which they were
  237.          * encountered in the makefile.
  238.          */
  239.         (void) Lst_AtEnd (nodes, (ClientData)gn);
  240.         if (gn->type & OP_DOUBLEDEP) {
  241.         (void)Lst_Concat (nodes, gn->cohorts, LST_CONCNEW);
  242.         }
  243.     } else if (flags == TARG_NOCREATE) {
  244.         Error ("\"%s\" -- target unknown.", name);
  245.     }
  246.     }
  247.     Lst_Close (names);
  248.     return (nodes);
  249. }
  250.  
  251. /*-
  252.  *-----------------------------------------------------------------------
  253.  * Targ_Ignore  --
  254.  *    Return true if should ignore errors when creating gn
  255.  *
  256.  * Results:
  257.  *    TRUE if should ignore errors
  258.  *
  259.  * Side Effects:
  260.  *    None
  261.  *-----------------------------------------------------------------------
  262.  */
  263. Boolean
  264. Targ_Ignore (gn)
  265.     GNode          *gn;        /* node to check for */
  266. {
  267.     if (ignoreErrors || gn->type & OP_IGNORE) {
  268.     return (TRUE);
  269.     } else {
  270.     return (FALSE);
  271.     }
  272. }
  273.  
  274. /*-
  275.  *-----------------------------------------------------------------------
  276.  * Targ_Silent  --
  277.  *    Return true if be silent when creating gn
  278.  *
  279.  * Results:
  280.  *    TRUE if should be silent
  281.  *
  282.  * Side Effects:
  283.  *    None
  284.  *-----------------------------------------------------------------------
  285.  */
  286. Boolean
  287. Targ_Silent (gn)
  288.     GNode          *gn;        /* node to check for */
  289. {
  290.     if (beSilent || gn->type & OP_SILENT) {
  291.     return (TRUE);
  292.     } else {
  293.     return (FALSE);
  294.     }
  295. }
  296.  
  297. /*-
  298.  *-----------------------------------------------------------------------
  299.  * Targ_Precious --
  300.  *    See if the given target is precious
  301.  *
  302.  * Results:
  303.  *    TRUE if it is precious. FALSE otherwise
  304.  *
  305.  * Side Effects:
  306.  *    None
  307.  *-----------------------------------------------------------------------
  308.  */
  309. Boolean
  310. Targ_Precious (gn)
  311.     GNode          *gn;        /* the node to check */
  312. {
  313.     if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) {
  314.     return (TRUE);
  315.     } else {
  316.     return (FALSE);
  317.     }
  318. }
  319.  
  320. /******************* DEBUG INFO PRINTING ****************/
  321.  
  322. static GNode      *mainTarg;    /* the main target, as set by Targ_SetMain */
  323. /*- 
  324.  *-----------------------------------------------------------------------
  325.  * Targ_SetMain --
  326.  *    Set our idea of the main target we'll be creating. Used for
  327.  *    debugging output.
  328.  *
  329.  * Results:
  330.  *    None.
  331.  *
  332.  * Side Effects:
  333.  *    "mainTarg" is set to the main target's node.
  334.  *-----------------------------------------------------------------------
  335.  */
  336. void
  337. Targ_SetMain (gn)
  338.     GNode   *gn;      /* The main target we'll create */
  339. {
  340.     mainTarg = gn;
  341. }
  342.  
  343. static int
  344. TargPrintName (gn, ppath)
  345.     GNode          *gn;
  346.     int            ppath;
  347. {
  348.     printf ("%s ", gn->name);
  349. #ifdef notdef
  350.     if (ppath) {
  351.     if (gn->path) {
  352.         printf ("[%s]  ", gn->path);
  353.     }
  354.     if (gn == mainTarg) {
  355.         printf ("(MAIN NAME)  ");
  356.     }
  357.     }
  358. #endif notdef
  359.     return (0);
  360. }
  361.  
  362.  
  363. int
  364. Targ_PrintCmd (cmd)
  365.     char           *cmd;
  366. {
  367.     printf ("\t%s\n", cmd);
  368.     return (0);
  369. }
  370.  
  371. /*-
  372.  *-----------------------------------------------------------------------
  373.  * Targ_FmtTime --
  374.  *    Format a modification time in some reasonable way and return it.
  375.  *
  376.  * Results:
  377.  *    The time reformatted.
  378.  *
  379.  * Side Effects:
  380.  *    The time is placed in a static area, so it is overwritten
  381.  *    with each call.
  382.  *
  383.  *-----------------------------------------------------------------------
  384.  */
  385. char *
  386. Targ_FmtTime (time)
  387.     time_t    time;
  388. {
  389.     struct tm          *parts;
  390.     static char          buf[40];
  391.     static char          *months[] = {
  392.     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  393.     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  394.     };
  395.  
  396.     parts = localtime(&time);
  397.  
  398.     sprintf (buf, "%d:%02d:%02d %s %d, 19%d",
  399.          parts->tm_hour, parts->tm_min, parts->tm_sec,
  400.          months[parts->tm_mon], parts->tm_mday, parts->tm_year);
  401.     return(buf);
  402. }
  403.     
  404. /*-
  405.  *-----------------------------------------------------------------------
  406.  * Targ_PrintType --
  407.  *    Print out a type field giving only those attributes the user can
  408.  *    set.
  409.  *
  410.  * Results:
  411.  *
  412.  * Side Effects:
  413.  *
  414.  *-----------------------------------------------------------------------
  415.  */
  416. void
  417. Targ_PrintType (type)
  418.     register int    type;
  419. {
  420.     register int    tbit;
  421.     
  422. #ifdef __STDC__
  423. #define PRINTBIT(attr)    case CONCAT(OP_,attr): printf("." #attr " "); break
  424. #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break
  425. #else
  426. #define PRINTBIT(attr)     case CONCAT(OP_,attr): printf(".attr "); break
  427. #define PRINTDBIT(attr)    case CONCAT(OP_,attr): if (DEBUG(TARG)) printf(".attr "); break
  428. #endif /* __STDC__ */
  429.  
  430.     type &= ~OP_OPMASK;
  431.  
  432.     while (type) {
  433.     tbit = 1 << (ffs(type) - 1);
  434.     type &= ~tbit;
  435.  
  436.     switch(tbit) {
  437.         PRINTBIT(OPTIONAL);
  438.         PRINTBIT(USE);
  439.         PRINTBIT(EXEC);
  440.         PRINTBIT(IGNORE);
  441.         PRINTBIT(PRECIOUS);
  442.         PRINTBIT(SILENT);
  443.         PRINTBIT(MAKE);
  444.         PRINTBIT(JOIN);
  445.         PRINTBIT(INVISIBLE);
  446.         PRINTBIT(NOTMAIN);
  447.         PRINTDBIT(LIB);
  448.         /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
  449.         case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break;
  450.         PRINTDBIT(ARCHV);
  451.     }
  452.     }
  453. }
  454.  
  455. /*-
  456.  *-----------------------------------------------------------------------
  457.  * TargPrintNode --
  458.  *    print the contents of a node
  459.  *-----------------------------------------------------------------------
  460.  */
  461. static int
  462. TargPrintNode (gn, pass)
  463.     GNode         *gn;
  464.     int              pass;
  465. {
  466.     if (!OP_NOP(gn->type)) {
  467.     printf("#\n");
  468.     if (gn == mainTarg) {
  469.         printf("# *** MAIN TARGET ***\n");
  470.     }
  471.     if (pass == 2) {
  472.         if (gn->unmade) {
  473.         printf("# %d unmade children\n", gn->unmade);
  474.         } else {
  475.         printf("# No unmade children\n");
  476.         }
  477.         if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
  478.         if (gn->mtime != 0) {
  479.             printf("# last modified %s: %s\n",
  480.                   Targ_FmtTime(gn->mtime),
  481.                   (gn->made == UNMADE ? "unmade" :
  482.                    (gn->made == MADE ? "made" :
  483.                 (gn->made == UPTODATE ? "up-to-date" :
  484.                  "error when made"))));
  485.         } else if (gn->made != UNMADE) {
  486.             printf("# non-existent (maybe): %s\n",
  487.                   (gn->made == MADE ? "made" :
  488.                    (gn->made == UPTODATE ? "up-to-date" :
  489.                 (gn->made == ERROR ? "error when made" :
  490.                  "aborted"))));
  491.         } else {
  492.             printf("# unmade\n");
  493.         }
  494.         }
  495.         if (!Lst_IsEmpty (gn->iParents)) {
  496.         printf("# implicit parents: ");
  497.         Lst_ForEach (gn->iParents, TargPrintName, (ClientData)0);
  498.         putc ('\n', stdout);
  499.         }
  500.     }
  501.     if (!Lst_IsEmpty (gn->parents)) {
  502.         printf("# parents: ");
  503.         Lst_ForEach (gn->parents, TargPrintName, (ClientData)0);
  504.         putc ('\n', stdout);
  505.     }
  506.     
  507.     printf("%-16s", gn->name);
  508.     switch (gn->type & OP_OPMASK) {
  509.         case OP_DEPENDS:
  510.         printf(": "); break;
  511.         case OP_FORCE:
  512.         printf("! "); break;
  513.         case OP_DOUBLEDEP:
  514.         printf(":: "); break;
  515.     }
  516.     Targ_PrintType (gn->type);
  517.     Lst_ForEach (gn->children, TargPrintName, (ClientData)0);
  518.     putc ('\n', stdout);
  519.     Lst_ForEach (gn->commands, Targ_PrintCmd, (ClientData)0);
  520.     printf("\n\n");
  521.     if (gn->type & OP_DOUBLEDEP) {
  522.         Lst_ForEach (gn->cohorts, TargPrintNode, (ClientData)pass);
  523.     }
  524.     }
  525.     return (0);
  526. }
  527.  
  528. /*-
  529.  *-----------------------------------------------------------------------
  530.  * TargPrintOnlySrc --
  531.  *    Print only those targets that are just a source.
  532.  *
  533.  * Results:
  534.  *    0.
  535.  *
  536.  * Side Effects:
  537.  *    The name of each file is printed preceeded by #\t
  538.  *
  539.  *-----------------------------------------------------------------------
  540.  */
  541. static int
  542. TargPrintOnlySrc(gn)
  543.     GNode         *gn;
  544. {
  545.     if (OP_NOP(gn->type)) {
  546.     printf("#\t%s [%s]\n", gn->name,
  547.           gn->path ? gn->path : gn->name);
  548.     }
  549.     return (0);
  550. }
  551.  
  552. /*-
  553.  *-----------------------------------------------------------------------
  554.  * Targ_PrintGraph --
  555.  *    print the entire graph. heh heh
  556.  *
  557.  * Results:
  558.  *    none
  559.  *
  560.  * Side Effects:
  561.  *    lots o' output
  562.  *-----------------------------------------------------------------------
  563.  */
  564. Targ_PrintGraph (pass)
  565.     int        pass;     /* Which pass this is. 1 => no processing
  566.              * 2 => processing done */
  567. {
  568.     printf("#*** Input graph:\n");
  569.     Lst_ForEach (allTargets, TargPrintNode, (ClientData)pass);
  570.     printf("\n\n");
  571.     printf("#\n#   Files that are only sources:\n");
  572.     Lst_ForEach (allTargets, TargPrintOnlySrc);
  573.     printf("#*** Global Variables:\n");
  574.     Var_Dump (VAR_GLOBAL);
  575.     printf("#*** Command-line Variables:\n");
  576.     Var_Dump (VAR_CMD);
  577.     printf("\n");
  578.     Dir_PrintDirectories();
  579.     printf("\n");
  580.     Suff_PrintAll();
  581. }
  582.