[BACK]Return to make.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / make

Diff for /src/usr.bin/make/make.c between version 1.39 and 1.40

version 1.39, 2007/09/17 08:36:57 version 1.40, 2007/09/17 08:53:59
Line 55 
Line 55 
  *                              place the parent on the toBeMade queue if it   *                              place the parent on the toBeMade queue if it
  *                              should be.   *                              should be.
  *   *
  *      Make_TimeStamp          Function to set the parent's cmtime field  
  *                              based on a child's modification time.  
  *  
  *      Make_DoAllVar           Set up the various local variables for a  
  *                              target, including the .ALLSRC variable, making  
  *                              sure that any variable that needs to exist  
  *                              at the very least has the empty value.  
  *  
  *      Make_OODate             Determine if a target is out-of-date.  
  *  
  *      Make_HandleUse          See if a child is a .USE node for a parent  
  *                              and perform the .USE actions if so.  
  */   */
   
 #include <limits.h>  #include <limits.h>
Line 98 
Line 86 
 static void MakeHandleUse(void *, void *);  static void MakeHandleUse(void *, void *);
 static bool MakeStartJobs(void);  static bool MakeStartJobs(void);
 static void MakePrintStatus(void *, void *);  static void MakePrintStatus(void *, void *);
   
 /*-  /*-
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  * MakeAddChild  --   * MakeAddChild  --
Line 109 
Line 98 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static void  static void
 MakeAddChild(  MakeAddChild(void *to_addp, void *lp)
     void *gnp,          /* the node to add */  
     void *lp)           /* the list to which to add it */  
 {  {
     GNode          *gn = (GNode *)gnp;          GNode      *to_add = (GNode *)to_addp;
     Lst            l = (Lst)lp;          Lst        l = (Lst)lp;
   
     if (!gn->make && !(gn->type & OP_USE))          if (!to_add->make && !(to_add->type & OP_USE))
         Lst_EnQueue(l, gn);                  Lst_EnQueue(l, to_add);
 }  }
   
 static void  static void
 MakeHandleUse(  MakeHandleUse(void *pgn, void *cgn)
     void *pgn,  /* the current parent */  
     void *cgn)  /* the child we've just examined */  
 {  {
     Make_HandleUse((GNode *)pgn, (GNode *)cgn);      Make_HandleUse((GNode *)pgn, (GNode *)cgn);
 }  }
Line 156 
Line 141 
 void  void
 Make_Update(GNode *cgn) /* the child node */  Make_Update(GNode *cgn) /* the child node */
 {  {
     GNode       *pgn;   /* the parent node */          GNode   *pgn;   /* the parent node */
     char        *cname; /* the child's name */          char    *cname; /* the child's name */
     LstNode     ln;     /* Element in parents and iParents lists */          LstNode ln;     /* Element in parents and iParents lists */
   
     cname = Varq_Value(TARGET_INDEX, cgn);          cname = Varq_Value(TARGET_INDEX, cgn);
   
     /*  
      * If the child was actually made, see what its modification time is  
      * now -- some rules won't actually update the file. If the file still  
      * doesn't exist, make its mtime now.  
      */  
     if (cgn->made != UPTODATE) {  
         /*          /*
          * This is what Make does and it's actually a good thing, as it           * If the child was actually made, see what its modification time is
          * allows rules like           * now -- some rules won't actually update the file. If the file still
          *           * doesn't exist, make its mtime now.
          *      cmp -s y.tab.h parse.h || cp y.tab.h parse.h  
          *  
          * to function as intended. Unfortunately, thanks to the stateless  
          * nature of NFS (by which I mean the loose coupling of two clients  
          * using the same file from a common server), there are times  
          * when the modification time of a file created on a remote  
          * machine will not be modified before the local stat() implied by  
          * the Dir_MTime occurs, thus leading us to believe that the file  
          * is unchanged, wreaking havoc with files that depend on this one.  
          *  
          * I have decided it is better to make too much than to make too  
          * little, so this stuff is commented out unless you're sure it's ok.  
          * -- ardeb 1/12/88  
          */           */
         /*          if (cgn->made != UPTODATE) {
          * Christos, 4/9/92: If we are  saving commands pretend that                  /*
          * the target is made now. Otherwise archives with ... rules                   * This is what Make does and it's actually a good thing, as it
          * don't work!                   * allows rules like
          */                   *
         if (noExecute || (cgn->type & OP_SAVE_CMDS) ||                   *      cmp -s y.tab.h parse.h || cp y.tab.h parse.h
             is_out_of_date(Dir_MTime(cgn))) {                   *
             cgn->mtime = now;                   * to function as intended. Unfortunately, thanks to the
                    * stateless nature of NFS, there are times when the
                    * modification time of a file created on a remote machine
                    * will not be modified before the local stat() implied by
                    * the Dir_MTime occurs, thus leading us to believe that the
                    * file is unchanged, wreaking havoc with files that depend
                    * on this one.
                    * XXX If we are saving commands pretend that
                    * the target is made now. Otherwise archives with ... rules
                    * don't work!
                    */
                   if (noExecute || (cgn->type & OP_SAVE_CMDS) ||
                       is_out_of_date(Dir_MTime(cgn)))
                           cgn->mtime = now;
                   if (DEBUG(MAKE))
                           printf("update time: %s\n", time_to_string(cgn->mtime));
         }          }
         if (DEBUG(MAKE)) {  
             printf("update time: %s\n", time_to_string(cgn->mtime));  
         }  
     }  
   
     for (ln = Lst_First(&cgn->parents); ln != NULL; ln = Lst_Adv(ln)) {          for (ln = Lst_First(&cgn->parents); ln != NULL; ln = Lst_Adv(ln)) {
         pgn = (GNode *)Lst_Datum(ln);                  pgn = (GNode *)Lst_Datum(ln);
         if (pgn->make) {                  if (pgn->make) {
             pgn->unmade--;                          pgn->unmade--;
   
             if ( ! (cgn->type & (OP_EXEC|OP_USE))) {                          if ( ! (cgn->type & (OP_EXEC|OP_USE))) {
                 if (cgn->made == MADE) {                                  if (cgn->made == MADE) {
                     pgn->childMade = true;                                          pgn->childMade = true;
                     if (is_strictly_before(pgn->cmtime, cgn->mtime))                                          if (is_strictly_before(pgn->cmtime,
                         pgn->cmtime = cgn->mtime;                                              cgn->mtime))
                 } else {                                                  pgn->cmtime = cgn->mtime;
                     (void)Make_TimeStamp(pgn, cgn);                                  } else {
                                           (void)Make_TimeStamp(pgn, cgn);
                                   }
                           }
                           if (pgn->unmade == 0) {
                                   /*
                                    * Queue the node up -- any unmade
                                    * predecessors will be dealt with in
                                    * MakeStartJobs.
                                    */
                                   Lst_EnQueue(&toBeMade, pgn);
                           } else if (pgn->unmade < 0) {
                                   Error("Graph cycles through %s", pgn->name);
                           }
                 }                  }
             }  
             if (pgn->unmade == 0) {  
                 /*  
                  * Queue the node up -- any unmade predecessors will  
                  * be dealt with in MakeStartJobs.  
                  */  
                 Lst_EnQueue(&toBeMade, pgn);  
             } else if (pgn->unmade < 0) {  
                 Error("Graph cycles through %s", pgn->name);  
             }  
         }          }
     }          /* Deal with successor nodes. If any is marked for making and has an
     /* Deal with successor nodes. If any is marked for making and has an unmade           * unmade count of 0, has not been made and isn't in the examination
      * count of 0, has not been made and isn't in the examination queue,           * queue, it means we need to place it in the queue as it restrained
      * it means we need to place it in the queue as it restrained itself           * itself before.       */
      * before.  */          for (ln = Lst_First(&cgn->successors); ln != NULL; ln = Lst_Adv(ln)) {
     for (ln = Lst_First(&cgn->successors); ln != NULL; ln = Lst_Adv(ln)) {                  GNode   *succ = (GNode *)Lst_Datum(ln);
         GNode   *succ = (GNode *)Lst_Datum(ln);  
   
         if (succ->make && succ->unmade == 0 && succ->made == UNMADE)                  if (succ->make && succ->unmade == 0 && succ->made == UNMADE)
             (void)Lst_QueueNew(&toBeMade, succ);                          (void)Lst_QueueNew(&toBeMade, succ);
     }          }
   
     /* Set the .PREFIX and .IMPSRC variables for all the implied parents          /* Set the .PREFIX and .IMPSRC variables for all the implied parents
      * of this node.  */           * of this node.  */
     {          {
     char        *cpref = Varq_Value(PREFIX_INDEX, cgn);          char    *cpref = Varq_Value(PREFIX_INDEX, cgn);
   
     for (ln = Lst_First(&cgn->iParents); ln != NULL; ln = Lst_Adv(ln)) {          for (ln = Lst_First(&cgn->iParents); ln != NULL; ln = Lst_Adv(ln)) {
         pgn = (GNode *)Lst_Datum(ln);                  pgn = (GNode *)Lst_Datum(ln);
         if (pgn->make) {                  if (pgn->make) {
             Varq_Set(IMPSRC_INDEX, cname, pgn);                          Varq_Set(IMPSRC_INDEX, cname, pgn);
             Varq_Set(PREFIX_INDEX, cpref, pgn);                          Varq_Set(PREFIX_INDEX, cpref, pgn);
                   }
         }          }
     }          }
     }  
 }  }
   
 /*-  /*
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  * MakeStartJobs --   * MakeStartJobs --
  *      Start as many jobs as possible.   *      Start as many jobs as possible.
Line 269 
Line 249 
 static bool  static bool
 MakeStartJobs(void)  MakeStartJobs(void)
 {  {
     GNode       *gn;          GNode   *gn;
   
     while (!Job_Full() && (gn = (GNode *)Lst_DeQueue(&toBeMade)) != NULL) {          while (!Job_Full() && (gn = (GNode *)Lst_DeQueue(&toBeMade)) != NULL) {
         if (DEBUG(MAKE)) {                  if (DEBUG(MAKE))
             printf("Examining %s...", gn->name);                          printf("Examining %s...", gn->name);
         }                  /*
         /*                   * Make sure any and all predecessors that are going to be made,
          * Make sure any and all predecessors that are going to be made,                   * have been.
          * have been.                   */
          */                  if (!Lst_IsEmpty(&gn->preds)) {
         if (!Lst_IsEmpty(&gn->preds)) {                          LstNode ln;
             LstNode ln;  
   
             for (ln = Lst_First(&gn->preds); ln != NULL; ln = Lst_Adv(ln)){                          for (ln = Lst_First(&gn->preds); ln != NULL;
                 GNode   *pgn = (GNode *)Lst_Datum(ln);                              ln = Lst_Adv(ln)){
                                   GNode   *pgn = (GNode *)Lst_Datum(ln);
   
                 if (pgn->make && pgn->made == UNMADE) {                                  if (pgn->make && pgn->made == UNMADE) {
                     if (DEBUG(MAKE)) {                                          if (DEBUG(MAKE))
                         printf("predecessor %s not made yet.\n", pgn->name);                                              printf("predecessor %s not made yet.\n", pgn->name);
                     }                                          break;
                     break;                                  }
                           }
                           /*
                            * If ln isn't NULL, there's a predecessor as yet
                            * unmade, so we just drop this node on the floor. When
                            * the node in question has been made, it will notice
                            * this node as being ready to make but as yet unmade
                            * and will place the node on the queue.
                            */
                           if (ln != NULL)
                                   continue;
                 }                  }
             }  
             /*  
              * If ln isn't NULL, there's a predecessor as yet unmade, so we  
              * just drop this node on the floor. When the node in question  
              * has been made, it will notice this node as being ready to  
              * make but as yet unmade and will place the node on the queue.  
              */  
             if (ln != NULL) {  
                 continue;  
             }  
         }  
   
         numNodes--;                  numNodes--;
         if (Make_OODate(gn)) {                  if (Make_OODate(gn)) {
             if (DEBUG(MAKE)) {                          if (DEBUG(MAKE))
                 printf("out-of-date\n");                                  printf("out-of-date\n");
             }                          if (queryFlag)
             if (queryFlag) {                                  return true;
                 return true;                          Make_DoAllVar(gn);
             }                          Job_Make(gn);
             Make_DoAllVar(gn);                  } else {
             Job_Make(gn);                          if (DEBUG(MAKE))
         } else {                                  printf("up-to-date\n");
             if (DEBUG(MAKE)) {                          gn->made = UPTODATE;
                 printf("up-to-date\n");                          if (gn->type & OP_JOIN) {
             }                                  /*
             gn->made = UPTODATE;                                   * Even for an up-to-date .JOIN node, we need it
             if (gn->type & OP_JOIN) {                                   * to have its context variables so references
                 /*                                   * to it get the correct value for .TARGET when
                  * Even for an up-to-date .JOIN node, we need it to have its                                   * building up the context variables of its
                  * context variables so references to it get the correct                                   * parent(s)...
                  * value for .TARGET when building up the context variables                                   */
                  * of its parent(s)...                                  Make_DoAllVar(gn);
                  */                          }
                 Make_DoAllVar(gn);  
             }  
   
             Make_Update(gn);                          Make_Update(gn);
                   }
         }          }
     }          return false;
     return false;  
 }  }
   
 /*-  /*-
Line 352 
Line 329 
                              * a cycle in the graph, not an error in an                               * a cycle in the graph, not an error in an
                              * inferior */                               * inferior */
 {  {
     GNode       *gn = (GNode *)gnp;          GNode   *gn = (GNode *)gnp;
     bool        cycle = *(bool *)cyclep;          bool    cycle = *(bool *)cyclep;
     if (gn->made == UPTODATE) {          if (gn->made == UPTODATE) {
         printf("`%s' is up to date.\n", gn->name);                  printf("`%s' is up to date.\n", gn->name);
     } else if (gn->unmade != 0) {          } else if (gn->unmade != 0) {
         if (cycle) {                  if (cycle) {
             bool t = true;                          bool t = true;
             /*                          /*
              * If printing cycles and came to one that has unmade children,                           * If printing cycles and came to one that has unmade
              * print out the cycle by recursing on its children. Note a                           * children, print out the cycle by recursing on its
              * cycle like:                           * children. Note a cycle like:
              *  a : b                           *      a : b
              *  b : c                           *      b : c
              *  c : b                           *      c : b
              * will cause this to erroneously complain about a being in                           * will cause this to erroneously complain about a
              * the cycle, but this is a good approximation.                           * being in the cycle, but this is a good approximation.
              */                           */
             if (gn->made == CYCLE) {                          if (gn->made == CYCLE) {
                 Error("Graph cycles through `%s'", gn->name);                                  Error("Graph cycles through `%s'", gn->name);
                 gn->made = ENDCYCLE;                                  gn->made = ENDCYCLE;
                 Lst_ForEach(&gn->children, MakePrintStatus, &t);                                  Lst_ForEach(&gn->children, MakePrintStatus, &t);
                 gn->made = UNMADE;                                  gn->made = UNMADE;
             } else if (gn->made != ENDCYCLE) {                          } else if (gn->made != ENDCYCLE) {
                 gn->made = CYCLE;                                  gn->made = CYCLE;
                 Lst_ForEach(&gn->children, MakePrintStatus, &t);                                  Lst_ForEach(&gn->children, MakePrintStatus, &t);
             }                          }
         } else {                  } else {
             printf("`%s' not remade because of errors.\n", gn->name);                          printf("`%s' not remade because of errors.\n",
                               gn->name);
                   }
         }          }
     }  
 }  }
   
   
Line 409 
Line 387 
 bool  bool
 Make_Run(Lst targs)             /* the initial list of targets */  Make_Run(Lst targs)             /* the initial list of targets */
 {  {
     GNode           *gn;        /* a temporary pointer */          GNode       *gn;        /* a temporary pointer */
     LIST            examine;    /* List of targets to examine */          LIST        examine;    /* List of targets to examine */
     int             errors;     /* Number of errors the Job module reports */          int         errors;     /* Number of errors the Job module reports */
   
     Static_Lst_Init(&toBeMade);          Static_Lst_Init(&toBeMade);
   
     Lst_Clone(&examine, targs, NOCOPY);          Lst_Clone(&examine, targs, NOCOPY);
     numNodes = 0;          numNodes = 0;
   
     /*          /*
      * Make an initial downward pass over the graph, marking nodes to be made           * Make an initial downward pass over the graph, marking nodes to be
      * as we go down. We call Suff_FindDeps to find where a node is and           * made as we go down. We call Suff_FindDeps to find where a node is and
      * to get some children for it if it has none and also has no commands.           * to get some children for it if it has none and also has no commands.
      * If the node is a leaf, we stick it on the toBeMade queue to           * If the node is a leaf, we stick it on the toBeMade queue to
      * be looked at in a minute, otherwise we add its children to our queue           * be looked at in a minute, otherwise we add its children to our queue
      * and go on about our business.           * and go on about our business.
      */           */
     while ((gn = (GNode *)Lst_DeQueue(&examine)) != NULL) {          while ((gn = (GNode *)Lst_DeQueue(&examine)) != NULL) {
         if (!gn->make) {                  if (!gn->make) {
             gn->make = true;                          gn->make = true;
             numNodes++;                          numNodes++;
   
             /*                          /*
              * Apply any .USE rules before looking for implicit dependencies                           * Apply any .USE rules before looking for implicit
              * to make sure everything has commands that should...                           * dependencies to make sure everything that should have
              */                           * commands has commands ...
             Lst_ForEach(&gn->children, MakeHandleUse, gn);                           */
             Suff_FindDeps(gn);                          Lst_ForEach(&gn->children, MakeHandleUse, gn);
                           Suff_FindDeps(gn);
   
             if (gn->unmade != 0) {                          if (gn->unmade != 0)
                 Lst_ForEach(&gn->children, MakeAddChild, &examine);                                  Lst_ForEach(&gn->children, MakeAddChild,
             } else {                                      &examine);
                 Lst_EnQueue(&toBeMade, gn);                          else
             }                                  Lst_EnQueue(&toBeMade, gn);
                   }
         }          }
     }  
   
     if (queryFlag) {          if (queryFlag) {
                   /*
                    * We wouldn't do any work unless we could start some jobs in
                    * the next loop... (we won't actually start any, of course,
                    * this is just to see if any of the targets was out of date)
                    */
                   return MakeStartJobs();
           } else {
                   /*
                    * Initialization. At the moment, no jobs are running and until
                    * some get started, nothing will happen since the remaining
                    * upward traversal of the graph is performed by the routines
                    * in job.c upon the finishing of a job. So we fill the Job
                    * table as much as we can before going into our loop.
                    */
                   (void)MakeStartJobs();
           }
   
         /*          /*
          * We wouldn't do any work unless we could start some jobs in the           * Main Loop: The idea here is that the ending of jobs will take
          * next loop... (we won't actually start any, of course, this is just           * care of the maintenance of data structures and the waiting for output
          * to see if any of the targets was out of date)           * will cause us to be idle most of the time while our children run as
            * much as possible. Because the job table is kept as full as possible,
            * the only time when it will be empty is when all the jobs which need
            * running have been run, so that is the end condition of this loop.
            * Note that the Job module will exit if there were any errors unless
            * the keepgoing flag was given.
          */           */
         return MakeStartJobs();          while (!Job_Empty()) {
     } else {                  Job_CatchOutput();
                   Job_CatchChildren(!usePipes);
                   (void)MakeStartJobs();
           }
   
           errors = Job_Finish();
   
         /*          /*
          * Initialization. At the moment, no jobs are running and until some           * Print the final status of each target. E.g. if it wasn't made
          * get started, nothing will happen since the remaining upward           * because some inferior reported an error.
          * traversal of the graph is performed by the routines in job.c upon  
          * the finishing of a job. So we fill the Job table as much as we can  
          * before going into our loop.  
          */           */
         (void)MakeStartJobs();          errors = errors == 0 && numNodes != 0;
     }          Lst_ForEach(targs, MakePrintStatus, &errors);
   
     /*          return true;
      * Main Loop: The idea here is that the ending of jobs will take  
      * care of the maintenance of data structures and the waiting for output  
      * will cause us to be idle most of the time while our children run as  
      * much as possible. Because the job table is kept as full as possible,  
      * the only time when it will be empty is when all the jobs which need  
      * running have been run, so that is the end condition of this loop.  
      * Note that the Job module will exit if there were any errors unless the  
      * keepgoing flag was given.  
      */  
     while (!Job_Empty()) {  
         Job_CatchOutput();  
         Job_CatchChildren(!usePipes);  
         (void)MakeStartJobs();  
     }  
   
     errors = Job_Finish();  
   
     /*  
      * Print the final status of each target. E.g. if it wasn't made  
      * because some inferior reported an error.  
      */  
     errors = errors == 0 && numNodes != 0;  
     Lst_ForEach(targs, MakePrintStatus, &errors);  
   
     return true;  
 }  }

Legend:
Removed from v.1.39  
changed lines
  Added in v.1.40