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

Diff for /src/usr.bin/make/arch.c between version 1.44 and 1.45

version 1.44, 2001/05/03 13:41:00 version 1.45, 2001/05/23 12:34:39
Line 66 
Line 66 
  * SUCH DAMAGE.   * SUCH DAMAGE.
  */   */
   
 /*-  /*
  * arch.c --  
  *      Functions to manipulate libraries, archives and their members.  
  *  
  *      Once again, cacheing/hashing comes into play in the manipulation   *      Once again, cacheing/hashing comes into play in the manipulation
  * of archives. The first time an archive is referenced, all of its members'   * of archives. The first time an archive is referenced, all of its members'
  * headers are read and hashed and the archive closed again. All hashed   * headers are read and hashed and the archive closed again. All hashed
  * archives are kept on a list which is searched each time an archive member   * archives are kept in a hash (archives) which is searched each time
  * is referenced.   * an archive member is referenced.
  *   *
  * The interface to this module is:  
  *      Arch_ParseArchive       Given an archive specification, return a list  
  *                              of GNode's, one for each member in the spec.  
  *                              FAILURE is returned if the specification is  
  *                              invalid for some reason.  
  *  
  *      Arch_Touch              Alter the modification time of the archive  
  *                              member described by the given node to be  
  *                              the current time.  
  *  
  *      Arch_TouchLib           Update the modification time of the library  
  *                              described by the given node. This is special  
  *                              because it also updates the modification time  
  *                              of the library's table of contents.  
  *  
  *      Arch_MTime              Find the modification time of a member of  
  *                              an archive *in the archive*. The time is also  
  *                              placed in the member's GNode. Returns the  
  *                              modification time.  
  *  
  *      Arch_MemMTime           Find the modification time of a member of  
  *                              an archive. Called when the member doesn't  
  *                              already exist. Looks in the archive for the  
  *                              modification time. Returns the modification  
  *                              time.  
  *  
  *      Arch_FindLib            Search for a library along a path. The  
  *                              library name in the GNode should be in  
  *                              -l<name> format.  
  *  
  *      Arch_LibOODate          Special function to decide if a library node  
  *                              is out-of-date.  
  *  
  *      Arch_Init               Initialize this module.  
  *  
  *      Arch_End                Cleanup this module.  
  */   */
   
 #include    <sys/types.h>  #include <sys/types.h>
 #include    <sys/stat.h>  #include <ar.h>
 #include    <sys/time.h>  #include <assert.h>
 #include    <sys/param.h>  #include <ctype.h>
 #include    <assert.h>  #include <fcntl.h>
 #include    <ctype.h>  #include <limits.h>
 #include    <ar.h>  #include <stddef.h>
 #include    <utime.h>  #include <stdio.h>
 #include    <stdio.h>  #include <stdlib.h>
 #include    <stddef.h>  #include <string.h>
 #include    <stdlib.h>  #include <unistd.h>
 #include    <fcntl.h>  #include "ohash.h"
 #include    "make.h"  #include "config.h"
 #include    "ohash.h"  #include "defines.h"
 #include    "dir.h"  #include "dir.h"
 #include    "config.h"  #include "arch.h"
   #include "var.h"
   #include "targ.h"
   #include "memory.h"
   #include "gnode.h"
   #include "timestamp.h"
   #include "lst.h"
   
 #ifndef lint  
 #if 0  
 static char sccsid[] = "@(#)arch.c      8.2 (Berkeley) 1/2/94";  
 #else  
 UNUSED  
 static char rcsid[] = "$OpenBSD$";  
 #endif  
 #endif /* not lint */  
   
   
 #ifdef TARGET_MACHINE  #ifdef TARGET_MACHINE
 #undef MACHINE  #undef MACHINE
 #define MACHINE TARGET_MACHINE  #define MACHINE TARGET_MACHINE
Line 191 
Line 148 
 #ifdef CLEANUP  #ifdef CLEANUP
 static void ArchFree(Arch *);  static void ArchFree(Arch *);
 #endif  #endif
 static TIMESTAMP ArchMTimeMember(const char *, const char *, Boolean);  static TIMESTAMP ArchMTimeMember(const char *, const char *, bool);
 static FILE *ArchFindMember(const char *, const char *, struct ar_hdr *, const char *);  static FILE *ArchFindMember(const char *, const char *, struct ar_hdr *, const char *);
 static void ArchTouch(const char *, const char *);  static void ArchTouch(const char *, const char *);
 #if defined(__svr4__) || defined(__SVR4) || \  #if defined(__svr4__) || defined(__SVR4) || \
Line 224 
Line 181 
     memcpy(n->date, &(hdr->ar_date), AR_DATE_SIZE);      memcpy(n->date, &(hdr->ar_date), AR_DATE_SIZE);
     n->date[AR_DATE_SIZE] = '\0';      n->date[AR_DATE_SIZE] = '\0';
     /* Don't compute mtime before it is needed. */      /* Don't compute mtime before it is needed. */
     set_out_of_date(n->mtime);      ts_set_out_of_date(n->mtime);
     return n;      return n;
 }  }
   
Line 233 
Line 190 
     struct arch_member *m;      struct arch_member *m;
 {  {
     if (is_out_of_date(m->mtime))      if (is_out_of_date(m->mtime))
         grab_date((time_t) strtol(m->date, NULL, 10), m->mtime);          ts_set_from_time_t((time_t) strtol(m->date, NULL, 10), m->mtime);
     return m->mtime;      return m->mtime;
 }  }
   
Line 263 
Line 220 
   
   
   
 /*-  /* Side-effects: Some nodes may be created.  */
  *-----------------------------------------------------------------------  bool
  * Arch_ParseArchive --  
  *      Parse the archive specification in the given line and find/create  
  *      the nodes for the specified archive members, placing their nodes  
  *      on the given list.  
  *  
  * Results:  
  *      SUCCESS if it was a valid specification. The linePtr is updated  
  *      to point to the first non-space after the archive spec. The  
  *      nodes for the members are placed on the given list.  
  *  
  * Side Effects:  
  *      Some nodes may be created. The given list is extended.  
  *-----------------------------------------------------------------------  
  */  
 ReturnStatus  
 Arch_ParseArchive(linePtr, nodeLst, ctxt)  Arch_ParseArchive(linePtr, nodeLst, ctxt)
     char            **linePtr;      /* Pointer to start of specification */      char            **linePtr;      /* Pointer to start of specification */
     Lst             nodeLst;        /* Lst on which to place the nodes */      Lst             nodeLst;        /* Lst on which to place the nodes */
Line 291 
Line 233 
     char            *memName;       /* Member-part of specification */      char            *memName;       /* Member-part of specification */
     char            nameBuf[MAKE_BSIZE]; /* temporary place for node name */      char            nameBuf[MAKE_BSIZE]; /* temporary place for node name */
     char            saveChar;       /* Ending delimiter of member-name */      char            saveChar;       /* Ending delimiter of member-name */
     Boolean         subLibName;     /* TRUE if libName should have/had      bool            subLibName;     /* true if libName should have/had
                                      * variable substitution performed on it */                                       * variable substitution performed on it */
   
     libName = *linePtr;      libName = *linePtr;
   
     subLibName = FALSE;      subLibName = false;
   
     for (cp = libName; *cp != '(' && *cp != '\0';) {      for (cp = libName; *cp != '(' && *cp != '\0';) {
         if (*cp == '$') {          if (*cp == '$') {
             ReturnStatus result;              bool ok;
   
             cp += Var_ParseSkip(cp, ctxt, &result);              cp += Var_ParseSkip(cp, ctxt, &ok);
             if (result == FAILURE)              if (ok == false)
                 return FAILURE;                  return false;
             subLibName = TRUE;              subLibName = true;
         } else          } else
             cp++;              cp++;
     }      }
   
     *cp++ = '\0';      *cp++ = '\0';
     if (subLibName)      if (subLibName)
         libName = Var_Subst(libName, ctxt, TRUE);          libName = Var_Subst(libName, ctxt, true);
   
     for (;;) {      for (;;) {
         /* First skip to the start of the member's name, mark that          /* First skip to the start of the member's name, mark that
          * place and skip to the end of it (either white-space or           * place and skip to the end of it (either white-space or
          * a close paren).  */           * a close paren).  */
         Boolean doSubst = FALSE; /* TRUE if need to substitute in memName */          bool doSubst = false; /* true if need to substitute in memName */
   
         while (*cp != '\0' && *cp != ')' && isspace(*cp))          while (*cp != '\0' && *cp != ')' && isspace(*cp))
             cp++;              cp++;
         memName = cp;          memName = cp;
         while (*cp != '\0' && *cp != ')' && !isspace(*cp)) {          while (*cp != '\0' && *cp != ')' && !isspace(*cp)) {
             if (*cp == '$') {              if (*cp == '$') {
                 ReturnStatus result;                  bool ok;
                 cp += Var_ParseSkip(cp, ctxt, &result);                  cp += Var_ParseSkip(cp, ctxt, &ok);
                 if (result == FAILURE)                  if (ok == false)
                     return FAILURE;                      return false;
                 doSubst = TRUE;                  doSubst = true;
             } else              } else
                 cp++;                  cp++;
         }          }
Line 340 
Line 282 
          * happen.  */           * happen.  */
         if (*cp == '\0') {          if (*cp == '\0') {
             printf("No closing parenthesis in archive specification\n");              printf("No closing parenthesis in archive specification\n");
             return FAILURE;              return false;
         }          }
   
         /* If we didn't move anywhere, we must be done.  */          /* If we didn't move anywhere, we must be done.  */
Line 364 
Line 306 
             char    *sacrifice;              char    *sacrifice;
             char    *oldMemName = memName;              char    *oldMemName = memName;
   
             memName = Var_Subst(memName, ctxt, TRUE);              memName = Var_Subst(memName, ctxt, true);
   
             /* Now form an archive spec and recurse to deal with nested              /* Now form an archive spec and recurse to deal with nested
              * variables and multi-word variable values.... The results               * variables and multi-word variable values.... The results
Line 377 
Line 319 
                 /* Must contain dynamic sources, so we can't deal with it now.                  /* Must contain dynamic sources, so we can't deal with it now.
                  * Just create an ARCHV node for the thing and let                   * Just create an ARCHV node for the thing and let
                  * SuffExpandChildren handle it...  */                   * SuffExpandChildren handle it...  */
                 gn = Targ_FindNode(buf, NULL, TARG_CREATE);                  gn = Targ_FindNode(buf, TARG_CREATE);
   
                 if (gn == NULL) {                  if (gn == NULL) {
                     free(buf);                      free(buf);
                     return FAILURE;                      return false;
                 } else {                  } else {
                     gn->type |= OP_ARCHV;                      gn->type |= OP_ARCHV;
                     Lst_AtEnd(nodeLst, gn);                      Lst_AtEnd(nodeLst, gn);
                 }                  }
             } else if (Arch_ParseArchive(&sacrifice, nodeLst, ctxt)!=SUCCESS) {              } else if (!Arch_ParseArchive(&sacrifice, nodeLst, ctxt)) {
                 /* Error in nested call -- free buffer and return FAILURE                  /* Error in nested call -- free buffer and return false
                  * ourselves.  */                   * ourselves.  */
                 free(buf);                  free(buf);
                 return FAILURE;                  return false;
             }              }
             /* Free buffer and continue with our work.  */              /* Free buffer and continue with our work.  */
             free(buf);              free(buf);
Line 400 
Line 342 
   
             Lst_Init(&members);              Lst_Init(&members);
   
             Dir_Expand(memName, &dirSearchPath, &members);              Dir_Expand(memName, dirSearchPath, &members);
             while ((member = (char *)Lst_DeQueue(&members)) != NULL) {              while ((member = (char *)Lst_DeQueue(&members)) != NULL) {
                 snprintf(nameBuf, MAKE_BSIZE, "%s(%s)", libName, member);                  snprintf(nameBuf, MAKE_BSIZE, "%s(%s)", libName, member);
                 free(member);                  free(member);
                 gn = Targ_FindNode(nameBuf, NULL, TARG_CREATE);                  gn = Targ_FindNode(nameBuf, TARG_CREATE);
                 /* We've found the node, but have to make sure the rest of                  /* We've found the node, but have to make sure the rest of
                  * the world knows it's an archive member, without having                   * the world knows it's an archive member, without having
                  * to constantly check for parentheses, so we type the                   * to constantly check for parentheses, so we type the
Line 415 
Line 357 
             }              }
         } else {          } else {
             snprintf(nameBuf, MAKE_BSIZE, "%s(%s)", libName, memName);              snprintf(nameBuf, MAKE_BSIZE, "%s(%s)", libName, memName);
             gn = Targ_FindNode(nameBuf, NULL, TARG_CREATE);              gn = Targ_FindNode(nameBuf, TARG_CREATE);
             /* We've found the node, but have to make sure the rest of the              /* We've found the node, but have to make sure the rest of the
              * world knows it's an archive member, without having to               * world knows it's an archive member, without having to
              * constantly check for parentheses, so we type the thing with               * constantly check for parentheses, so we type the thing with
Line 442 
Line 384 
     } while (*cp != '\0' && isspace(*cp));      } while (*cp != '\0' && isspace(*cp));
   
     *linePtr = cp;      *linePtr = cp;
     return SUCCESS;      return true;
 }  }
   
 /* Helper function: ar fields are not null terminated.  */  /* Helper function: ar fields are not null terminated.  */
Line 598 
Line 540 
  *      out of date).   *      out of date).
  *   *
  * Side Effects:   * Side Effects:
  *      Cache the whole archive contents if hash is TRUE.   *      Cache the whole archive contents if hash is true.
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static TIMESTAMP  static TIMESTAMP
Line 606 
Line 548 
     const char    *archive;   /* Path to the archive */      const char    *archive;   /* Path to the archive */
     const char    *member;    /* Name of member. If it is a path, only the      const char    *member;    /* Name of member. If it is a path, only the
                                * last component is used. */                                 * last component is used. */
     Boolean       hash;       /* TRUE if archive should be hashed if not      bool          hash;       /* true if archive should be hashed if not
                                * already so. */                                 * already so. */
 {  {
     FILE *        arch;       /* Stream to archive */      FILE *        arch;       /* Stream to archive */
Line 616 
Line 558 
     const char    *cp;      const char    *cp;
     TIMESTAMP     result;      TIMESTAMP     result;
   
     set_out_of_date(result);      ts_set_out_of_date(result);
     /* Because of space constraints and similar things, files are archived      /* Because of space constraints and similar things, files are archived
      * using their final path components, not the entire thing, so we need       * using their final path components, not the entire thing, so we need
      * to point 'member' to the final component, if there is one, to make       * to point 'member' to the final component, if there is one, to make
Line 641 
Line 583 
   
             if (arch != NULL) {              if (arch != NULL) {
                 fclose(arch);                  fclose(arch);
                 grab_date( (time_t)strtol(sarh.ar_date, NULL, 10), result);                  ts_set_from_time_t( (time_t)strtol(sarh.ar_date, NULL, 10), result);
             }              }
             return result;              return result;
         }          }
Line 934 
Line 876 
     }      }
 }  }
   
 /*-  /*
  *-----------------------------------------------------------------------  
  * Arch_Touch --  
  *      Touch a member of an archive.  
  *  
  * Side Effects:   * Side Effects:
  *      The 'time' field of the member's header is updated.  
  *      The modification time of the entire archive is also changed.   *      The modification time of the entire archive is also changed.
  *      For a library, this could necessitate the re-ranlib'ing of the   *      For a library, this could necessitate the re-ranlib'ing of the
  *      whole thing.   *      whole thing.
  *-----------------------------------------------------------------------  
  */   */
 void  void
 Arch_Touch(gn)  Arch_Touch(gn)
Line 953 
Line 889 
     ArchTouch(Varq_Value(ARCHIVE_INDEX, gn), Varq_Value(MEMBER_INDEX, gn));      ArchTouch(Varq_Value(ARCHIVE_INDEX, gn), Varq_Value(MEMBER_INDEX, gn));
 }  }
   
 /*-  
  *-----------------------------------------------------------------------  
  * Arch_TouchLib --  
  *      Given a node which represents a library, touch the thing, making  
  *      sure that the table of contents also is touched.  
  *  
  * Side Effects:  
  *      The modification time of the library and of the RANLIBMAG  
  *      member are set to 'now'.  
  *-----------------------------------------------------------------------  
  */  
 void  void
 Arch_TouchLib(gn)  Arch_TouchLib(gn)
     GNode           *gn;        /* The node of the library to touch */      GNode           *gn;        /* The node of the library to touch */
Line 976 
Line 901 
 #endif  #endif
 }  }
   
 /*-  
  *-----------------------------------------------------------------------  
  * Arch_MTime --  
  *      Return the modification time of a member of an archive.  
  *  
  * Results:  
  *      The modification time.  
  *  
  * Side Effects:  
  *      The mtime field of the given node is filled in with the value  
  *      returned by the function.  
  *-----------------------------------------------------------------------  
  */  
 TIMESTAMP  TIMESTAMP
 Arch_MTime(gn)  Arch_MTime(gn)
     GNode         *gn;        /* Node describing archive member */      GNode         *gn;        /* Node describing archive member */
 {  {
     gn->mtime = ArchMTimeMember(Varq_Value(ARCHIVE_INDEX, gn),      gn->mtime = ArchMTimeMember(Varq_Value(ARCHIVE_INDEX, gn),
              Varq_Value(MEMBER_INDEX, gn),               Varq_Value(MEMBER_INDEX, gn),
              TRUE);               true);
   
     return gn->mtime;      return gn->mtime;
 }  }
   
 /*-  
  *-----------------------------------------------------------------------  
  * Arch_MemMTime --  
  *      Given a non-existent archive member's node, get its modification  
  *      time from its archived form, if it exists.  
  *  
  * Results:  
  *      The modification time.  
  *  
  * Side Effects:  
  *      The mtime field is filled in.  
  *-----------------------------------------------------------------------  
  */  
 TIMESTAMP  TIMESTAMP
 Arch_MemMTime(gn)  Arch_MemMTime(gn)
     GNode         *gn;      GNode         *gn;
Line 1045 
Line 944 
         } else if (pgn->make) {          } else if (pgn->make) {
             /* Something which isn't a library depends on the existence of              /* Something which isn't a library depends on the existence of
              * this target, so it needs to exist.  */               * this target, so it needs to exist.  */
             set_out_of_date(gn->mtime);              ts_set_out_of_date(gn->mtime);
             break;              break;
         }          }
     }      }
     return gn->mtime;      return gn->mtime;
 }  }
   
 /*-  /* If the system can handle the -L flag when linking (or we cannot find
  *-----------------------------------------------------------------------   * the library), we assume that the user has placed the .LIBRARIES variable
  * Arch_FindLib --   * in the final linking command (or the linker will know where to find it)
  *      Search for a library along the given search path.   * and set the TARGET variable for this node to be the node's name. Otherwise,
  *   * we set the TARGET variable to be the full path of the library,
  * Side Effects:   * as returned by Dir_FindFile.
  *      The node's 'path' field is set to the found path (including the  
  *      actual file name, not -l...). If the system can handle the -L  
  *      flag when linking (or we cannot find the library), we assume that  
  *      the user has placed the .LIBRARIES variable in the final linking  
  *      command (or the linker will know where to find it) and set the  
  *      TARGET variable for this node to be the node's name. Otherwise,  
  *      we set the TARGET variable to be the full path of the library,  
  *      as returned by Dir_FindFile.  
  *-----------------------------------------------------------------------  
  */   */
 void  void
 Arch_FindLib(gn, path)  Arch_FindLib(gn, path)
Line 1118 
Line 1008 
  *                TOC.   *                TOC.
  *   *
  * Results:   * Results:
  *      TRUE if the library is out-of-date. FALSE otherwise.   *      true if the library is out-of-date. false otherwise.
  *   *
  * Side Effects:   * Side Effects:
  *      The library will be hashed if it hasn't been already.   *      The library will be hashed if it hasn't been already.
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 Boolean  bool
 Arch_LibOODate(gn)  Arch_LibOODate(gn)
     GNode         *gn;          /* The library's graph node */      GNode         *gn;          /* The library's graph node */
 {  {
     TIMESTAMP     modTimeTOC;   /* mod time of __.SYMDEF */      TIMESTAMP     modTimeTOC;   /* mod time of __.SYMDEF */
   
     if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->children))      if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->children))
         return FALSE;          return false;
     if (is_before(now, gn->mtime) || is_before(gn->mtime, gn->cmtime) ||      if (is_strictly_before(now, gn->mtime) || is_strictly_before(gn->mtime, gn->cmtime) ||
         is_out_of_date(gn->mtime))          is_out_of_date(gn->mtime))
         return TRUE;          return true;
 #ifdef RANLIBMAG  #ifdef RANLIBMAG
     /* non existent libraries are always out-of-date.  */      /* non existent libraries are always out-of-date.  */
     if (gn->path == NULL)      if (gn->path == NULL)
         return TRUE;          return true;
     modTimeTOC = ArchMTimeMember(gn->path, RANLIBMAG, FALSE);      modTimeTOC = ArchMTimeMember(gn->path, RANLIBMAG, false);
   
     if (!is_out_of_date(modTimeTOC)) {      if (!is_out_of_date(modTimeTOC)) {
         if (DEBUG(ARCH) || DEBUG(MAKE))          if (DEBUG(ARCH) || DEBUG(MAKE))
             printf("%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC));              printf("%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC));
         return is_before(modTimeTOC, gn->cmtime);          return is_strictly_before(modTimeTOC, gn->cmtime);
     }      }
     /* A library w/o a table of contents is out-of-date.  */      /* A library w/o a table of contents is out-of-date.  */
     if (DEBUG(ARCH) || DEBUG(MAKE))      if (DEBUG(ARCH) || DEBUG(MAKE))
         printf("No t.o.c....");          printf("No t.o.c....");
     return TRUE;      return true;
 #else  #else
     return FALSE;      return false;
 #endif  #endif
 }  }
   
 /*-  
  *-----------------------------------------------------------------------  
  * Arch_Init --  
  *      Initialize things for this module.  
  *  
  * Side Effects:  
  *      The 'archives' hash is initialized.  
  *-----------------------------------------------------------------------  
  */  
 void  void
 Arch_Init()  Arch_Init()
 {  {
     ohash_init(&archives, 4, &arch_info);      ohash_init(&archives, 4, &arch_info);
 }  }
   
   #ifdef CLEANUP
   
 /*-  
  *-----------------------------------------------------------------------  
  * Arch_End --  
  *      Cleanup things for this module.  
  *  
  * Side Effects:  
  *      The 'archives' hash is freed  
  *-----------------------------------------------------------------------  
  */  
 void  void
 Arch_End()  Arch_End()
 {  {
 #ifdef CLEANUP  
     Arch *e;      Arch *e;
     unsigned int i;      unsigned int i;
   
Line 1192 
Line 1062 
         e = ohash_next(&archives, &i))          e = ohash_next(&archives, &i))
             ArchFree(e);              ArchFree(e);
     ohash_delete(&archives);      ohash_delete(&archives);
 #endif  
 }  }
   #endif
   
 /*-  bool
  *-----------------------------------------------------------------------  
  * Arch_IsLib --  
  *      Check if the node is a library  
  *  
  * Results:  
  *      True or False.  
  *-----------------------------------------------------------------------  
  */  
 Boolean  
 Arch_IsLib(gn)  Arch_IsLib(gn)
     GNode *gn;      GNode *gn;
 {  {
Line 1212 
Line 1073 
     int fd;      int fd;
   
     if (gn->path == NULL || (fd = open(gn->path, O_RDONLY)) == -1)      if (gn->path == NULL || (fd = open(gn->path, O_RDONLY)) == -1)
         return FALSE;          return false;
   
     if (read(fd, buf, SARMAG) != SARMAG) {      if (read(fd, buf, SARMAG) != SARMAG) {
         (void)close(fd);          (void)close(fd);
         return FALSE;          return false;
     }      }
   
     (void)close(fd);      (void)close(fd);

Legend:
Removed from v.1.44  
changed lines
  Added in v.1.45