Add support for thin archives.
authorNick Clifton <nickc@redhat.com>
Fri, 28 Mar 2008 06:49:44 +0000 (06:49 +0000)
committerNick Clifton <nickc@redhat.com>
Fri, 28 Mar 2008 06:49:44 +0000 (06:49 +0000)
    * bfd/archive.c (_bfd_find_nested_archive): New function.
    (get_extended_arelt_filename): Add origin parameter.
    (_bfd_generic_read_ar_hdr_mag): Deal with extended name
    combined with a file offset.
    (append_relative_path): New function.
    (_bfd_get_elt_at_filepos): Deal with external members and
    nested archives.
    (bfd_generic_openr_next_archived_file): Thin archives.
    (bfd_generic_archive_p): Recognize new magic string.
    (adjust_relative_path): New function.
    (_bfd_construct_extended_name_table): Construct extended
    names for thin archive members.
    (_bfd_write_archive_contents): Emit new magic string, skip
    copying files for thin archives.
    * bfd/bfd-in.h (bfd_is_thin_archive): New macro.
    * bfd/bfd.c (struct bfd): New fields for thin archives.
    * bfd/libbfd-in.h (struct areltdata): New field for thin archives.
    * bfd/opncls.c (bfd_close): Delete BFDs for nested archives.
    * binutils/ar.c (make_thin_archive): New global flag.
    (map_over_members): Deal with full pathnames in thin archives.
    (usage, main): Add 'T' option for building thin archives.
    (replace_members): Pass thin archive flag to ar_emul_append.
    * binutils/arsup.c (ar_open): Initialize new flag.
    * binutils/binemul.c (ar_emul_append): Add new parameter for
    flattening nested archives.
    (do_ar_emul_default_append): New function.
    (ar_emul_default_append): Factored out recursive code.
    * binutils/binemul.h (ar_emul_default_append): Add new parameter.
    (struct bin_emulation_xfer_struct): New parameter for ar_append.
    * binutils/dlltool.c (gen_lib_file): Initialize thin archive flag.
    * binutils/emul_aix.c (ar_emul_aix_internal): Add new flatten
    parameter, currently unimplemented.
    All callers changed.
    * binutils/objcopy.c (copy_archive): Preserve thin archive flag.
    * binutils/doc/binutils.texi: Update ar documentation.
    * binutils/testsuite/binutils-all/ar.exp: Add thin archive tests.
    * include/aout/ar.h (ARMAGT): New magic string for thin archives.

22 files changed:
bfd/ChangeLog
bfd/archive.c
bfd/bfd-in.h
bfd/bfd-in2.h
bfd/bfd.c
bfd/libbfd-in.h
bfd/libbfd.h
bfd/opncls.c
binutils/ChangeLog
binutils/NEWS
binutils/ar.c
binutils/arsup.c
binutils/binemul.c
binutils/binemul.h
binutils/dlltool.c
binutils/doc/binutils.texi
binutils/emul_aix.c
binutils/objcopy.c
binutils/testsuite/ChangeLog
binutils/testsuite/binutils-all/ar.exp
include/aout/ChangeLog
include/aout/ar.h

index 55514b43c348f5d5073800c89056371f775875e5..063a304e55faa6c32a5b27bbbcb1354fbb86459a 100644 (file)
@@ -1,3 +1,25 @@
+2008-03-27  Cary Coutant <ccoutant@google.com>
+
+        Add support for thin archives.
+       * archive.c (_bfd_find_nested_archive): New function.
+       (get_extended_arelt_filename): Add origin parameter.
+       (_bfd_generic_read_ar_hdr_mag): Deal with extended name
+       combined with a file offset.
+       (append_relative_path): New function.
+       (_bfd_get_elt_at_filepos): Deal with external members and
+       nested archives.
+       (bfd_generic_openr_next_archived_file): Thin archives.
+       (bfd_generic_archive_p): Recognize new magic string.
+       (adjust_relative_path): New function.
+       (_bfd_construct_extended_name_table): Construct extended
+       names for thin archive members.
+       (_bfd_write_archive_contents): Emit new magic string, skip
+       copying files for thin archives.
+       * bfd-in.h (bfd_is_thin_archive): New macro.
+       * bfd.c (struct bfd): New fields for thin archives.
+       * libbfd-in.h (struct areltdata): New field for thin archives.
+       * opncls.c (bfd_close): Delete BFDs for nested archives.
+
 2008-03-25  Bernd Schmidt  <bernd.schmidt@analog.com>
 
        * elf32-bfin.c (bfin_final_link_relocate): New function, wrapper around
index e080d3a301da737cc320005239e8d584a5a7003e..5389f7adcc5b983850c4f9a596f834871d528292 100644 (file)
@@ -1,6 +1,6 @@
 /* BFD back-end for archive files (libraries).
    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
    Written by Cygnus Support.  Mostly Gumby Henkel-Wallace's fault.
 
@@ -137,6 +137,7 @@ SUBSECTION
 #include "aout/ranlib.h"
 #include "safe-ctype.h"
 #include "hashtab.h"
+#include "filenames.h"
 
 #ifndef errno
 extern int errno;
@@ -157,7 +158,7 @@ struct ar_cache {
 #define ar_maxnamelen(abfd) ((abfd)->xvec->ar_max_namelen)
 
 #define arch_eltdata(bfd) ((struct areltdata *) ((bfd)->arelt_data))
-#define arch_hdr(bfd) ((struct ar_hdr *) arch_eltdata(bfd)->arch_header)
+#define arch_hdr(bfd) ((struct ar_hdr *) arch_eltdata (bfd)->arch_header)
 \f
 void
 _bfd_ar_spacepad (char *p, size_t n, const char *fmt, long val)
@@ -326,24 +327,61 @@ _bfd_add_bfd_to_archive_cache (bfd *arch_bfd, file_ptr filepos, bfd *new_elt)
   return TRUE;
 }
 \f
+static bfd *
+_bfd_find_nested_archive (bfd *arch_bfd, const char *filename)
+{
+  bfd *abfd;
+
+  for (abfd = arch_bfd->nested_archives;
+       abfd != NULL;
+       abfd = abfd->archive_next)
+    {
+      if (strcmp (filename, abfd->filename) == 0)
+        return abfd;
+    }
+  abfd = bfd_openr (filename, NULL);
+  if (abfd)
+    {
+      abfd->archive_next = arch_bfd->nested_archives;
+      arch_bfd->nested_archives = abfd;
+    }
+  return abfd;
+}
+
 /* The name begins with space.  Hence the rest of the name is an index into
    the string table.  */
 
 static char *
-get_extended_arelt_filename (bfd *arch, const char *name)
+get_extended_arelt_filename (bfd *arch, const char *name, file_ptr *originp)
 {
   unsigned long index = 0;
+  const char *endp;
 
   /* Should extract string so that I can guarantee not to overflow into
      the next region, but I'm too lazy.  */
   errno = 0;
   /* Skip first char, which is '/' in SVR4 or ' ' in some other variants.  */
-  index = strtol (name + 1, NULL, 10);
+  index = strtol (name + 1, (char **) &endp, 10);
   if (errno != 0 || index >= bfd_ardata (arch)->extended_names_size)
     {
       bfd_set_error (bfd_error_malformed_archive);
       return NULL;
     }
+  /* In a thin archive, a member of an archive-within-an-archive
+     will have the offset in the inner archive encoded here.  */
+  if (bfd_is_thin_archive (arch) && endp != NULL && *endp == ':')
+    {
+      file_ptr origin = strtol (endp + 1, NULL, 10);
+
+      if (errno != 0 || index >= bfd_ardata (arch)->extended_names_size)
+        {
+          bfd_set_error (bfd_error_malformed_archive);
+          return NULL;
+        }
+      *originp = origin;
+    }
+  else
+    *originp = 0;
 
   return bfd_ardata (arch)->extended_names + index;
 }
@@ -376,6 +414,7 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag)
   bfd_size_type namelen = 0;
   bfd_size_type allocsize = sizeof (struct areltdata) + sizeof (struct ar_hdr);
   char *allocptr = 0;
+  file_ptr origin = 0;
 
   if (bfd_bread (hdrp, sizeof (struct ar_hdr), abfd) != sizeof (struct ar_hdr))
     {
@@ -407,7 +446,7 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag)
           && memchr (hdr.ar_name, '/', ar_maxnamelen (abfd)) == NULL))
       && bfd_ardata (abfd)->extended_names != NULL)
     {
-      filename = get_extended_arelt_filename (abfd, hdr.ar_name);
+      filename = get_extended_arelt_filename (abfd, hdr.ar_name, &origin);
       if (filename == NULL)
        return NULL;
     }
@@ -476,6 +515,7 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag)
   ared->arch_header = allocptr + sizeof (struct areltdata);
   memcpy (ared->arch_header, &hdr, sizeof (struct ar_hdr));
   ared->parsed_size = parsed_size;
+  ared->origin = origin;
 
   if (filename != NULL)
     ared->filename = filename;
@@ -491,6 +531,30 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag)
   return ared;
 }
 \f
+/* Append the relative pathname for a member of the thin archive
+   to the pathname of the directory containing the archive.  */
+
+static char *
+append_relative_path (bfd *arch, char *elt_name)
+{
+  const char *arch_name = arch->filename;
+  const char *base_name = lbasename (arch_name);
+  size_t prefix_len;
+  char *filename;
+
+  if (base_name == arch_name)
+    return elt_name;
+
+  prefix_len = base_name - arch_name;
+  filename = bfd_alloc (arch, prefix_len + strlen (elt_name) + 1);
+  if (filename == NULL)
+    return NULL;
+
+  strncpy (filename, arch_name, prefix_len);
+  strcpy (filename + prefix_len, elt_name);
+  return filename;
+}
+
 /* This is an internal function; it's mainly used when indexing
    through the archive symbol table, but also used to get the next
    element, since it handles the bookkeeping so nicely for us.  */
@@ -500,6 +564,7 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos)
 {
   struct areltdata *new_areldata;
   bfd *n_nfd;
+  char *filename;
 
   if (archive->my_archive)
     {
@@ -517,21 +582,74 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos)
   if ((new_areldata = _bfd_read_ar_hdr (archive)) == NULL)
     return NULL;
 
-  n_nfd = _bfd_create_empty_archive_element_shell (archive);
+  filename = new_areldata->filename;
+
+  if (bfd_is_thin_archive (archive))
+    {
+      /* This is a proxy entry for an external file.  */
+      if (! IS_ABSOLUTE_PATH (filename))
+        {
+          filename = append_relative_path (archive, filename);
+          if (filename == NULL)
+            return NULL;
+        }
+
+      if (new_areldata->origin > 0)
+        {
+          /* This proxy entry refers to an element of a nested archive.
+             Locate the member of that archive and return a bfd for it.  */
+          bfd *ext_arch = _bfd_find_nested_archive (archive, filename);
+
+          if (ext_arch == NULL
+              || ! bfd_check_format (ext_arch, bfd_archive))
+            {
+              bfd_release (archive, new_areldata);
+              return NULL;
+            }
+          n_nfd = _bfd_get_elt_at_filepos (ext_arch, new_areldata->origin);
+          if (n_nfd == NULL)
+            {
+              bfd_release (archive, new_areldata);
+              return NULL;
+            }
+          n_nfd->proxy_origin = bfd_tell (archive);
+          return n_nfd;
+        }
+      /* It's not an element of a nested archive;
+         open the external file as a bfd.  */
+      n_nfd = bfd_openr (filename, NULL);
+    }
+  else
+    {
+      n_nfd = _bfd_create_empty_archive_element_shell (archive);
+    }
+
   if (n_nfd == NULL)
     {
       bfd_release (archive, new_areldata);
       return NULL;
     }
 
-  n_nfd->origin = bfd_tell (archive);
+  n_nfd->proxy_origin = bfd_tell (archive);
+
+  if (bfd_is_thin_archive (archive))
+    {
+      n_nfd->origin = 0;
+    }
+  else
+    {
+      n_nfd->origin = n_nfd->proxy_origin;
+      n_nfd->filename = filename;
+    }
+
   n_nfd->arelt_data = new_areldata;
-  n_nfd->filename = new_areldata->filename;
 
   if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_nfd))
     return n_nfd;
 
   /* Huh?  */
+  /* FIXME:  n_nfd isn't allocated in the archive's memory pool.
+     If we reach this point, I think bfd_release will abort.  */
   bfd_release (archive, n_nfd);
   bfd_release (archive, new_areldata);
   return NULL;
@@ -568,8 +686,8 @@ DESCRIPTION
 bfd *
 bfd_openr_next_archived_file (bfd *archive, bfd *last_file)
 {
-  if ((bfd_get_format (archive) != bfd_archive) ||
-      (archive->direction == write_direction))
+  if ((bfd_get_format (archive) != bfd_archive)
+      || (archive->direction == write_direction))
     {
       bfd_set_error (bfd_error_invalid_operation);
       return NULL;
@@ -589,7 +707,9 @@ bfd_generic_openr_next_archived_file (bfd *archive, bfd *last_file)
   else
     {
       unsigned int size = arelt_size (last_file);
-      filestart = last_file->origin + size;
+      filestart = last_file->proxy_origin;
+      if (! bfd_is_thin_archive (archive))
+        filestart += size;
       if (archive->my_archive)
        filestart -= archive->origin;
       /* Pad to an even boundary...
@@ -615,8 +735,11 @@ bfd_generic_archive_p (bfd *abfd)
       return NULL;
     }
 
-  if (strncmp (armag, ARMAG, SARMAG) != 0 &&
-      strncmp (armag, ARMAGB, SARMAG) != 0)
+  bfd_is_thin_archive (abfd) = (strncmp (armag, ARMAGT, SARMAG) == 0);
+
+  if (strncmp (armag, ARMAG, SARMAG) != 0
+      && strncmp (armag, ARMAGB, SARMAG) != 0
+      && ! bfd_is_thin_archive (abfd))
     return 0;
 
   tdata_hold = bfd_ardata (abfd);
@@ -1110,7 +1233,7 @@ _bfd_slurp_extended_name_table (bfd *abfd)
        char *limit = temp + namedata->parsed_size;
        for (; temp < limit; ++temp)
          {
-           if (*temp == '\012')
+           if (*temp == ARFMAG[0])
              temp[temp > ext_names && temp[-1] == '/' ? -1 : 0] = '\0';
            if (*temp == '\\')
              *temp = '/';
@@ -1190,6 +1313,66 @@ normalize (bfd *abfd ATTRIBUTE_UNUSED, const char *file)
 }
 #endif
 
+/* Adjust a relative path name based on the reference path.  */
+
+static const char *
+adjust_relative_path (const char * path, const char * ref_path)
+{
+  static char *pathbuf = NULL;
+  static int pathbuf_len = 0;
+  const char *pathp = path;
+  const char *refp = ref_path;
+  int element_count = 0;
+  int len;
+  char *newp;
+
+  /* Remove common leading path elements.  */
+  for (;;)
+    {
+      const char *e1 = pathp;
+      const char *e2 = refp;
+
+      while (*e1 && ! IS_DIR_SEPARATOR (*e1))
+       ++e1;
+      while (*e2 && ! IS_DIR_SEPARATOR (*e2))
+       ++e2;
+      if (*e1 == '\0' || *e2 == '\0' || e1 - pathp != e2 - refp
+         || strncmp (pathp, refp, e1 - pathp) != 0)
+       break;
+      pathp = e1 + 1;
+      refp = e2 + 1;
+    }
+
+  /* For each leading path element in the reference path,
+     insert "../" into the path.  */
+  for (; *refp; ++refp)
+    if (IS_DIR_SEPARATOR (*refp))
+      ++element_count;
+  len = 3 * element_count + strlen (path) + 1;
+
+  if (len > pathbuf_len)
+    {
+      if (pathbuf != NULL)
+       free (pathbuf);
+      pathbuf_len = 0;
+      pathbuf = bfd_malloc (len);
+      if (pathbuf == NULL)
+       return path;
+      pathbuf_len = len;
+    }
+
+  newp = pathbuf;
+  while (element_count-- > 0)
+    {
+      /* FIXME: Support Windows style path separators as well.  */
+      strcpy (newp, "../");
+      newp += 3;
+    }
+  strcpy (newp, pathp);
+
+  return pathbuf;
+}
+
 /* Build a BFD style extended name table.  */
 
 bfd_boolean
@@ -1232,8 +1415,11 @@ _bfd_construct_extended_name_table (bfd *abfd,
   bfd_size_type total_namelen = 0;
   bfd *current;
   char *strptr;
+  const char *last_filename;
+  long last_stroff;
 
   *tablen = 0;
+  last_filename = NULL;
 
   /* Figure out how long the table should be.  */
   for (current = abfd->archive_head;
@@ -1243,6 +1429,42 @@ _bfd_construct_extended_name_table (bfd *abfd,
       const char *normal;
       unsigned int thislen;
 
+      if (bfd_is_thin_archive (abfd))
+        {
+          const char *filename = current->filename;
+
+          /* If the element being added is a member of another archive
+             (i.e., we are flattening), use the containing archive's name.  */
+          if (current->my_archive
+              && ! bfd_is_thin_archive (current->my_archive))
+            filename = current->my_archive->filename;
+
+          /* If the path is the same as the previous path seen,
+             reuse it.  This can happen when flattening a thin
+             archive that contains other archives.  */
+          if (last_filename && strcmp (last_filename, filename) == 0)
+            continue;
+
+          last_filename = filename;
+
+          /* If the path is relative, adjust it relative to
+             the containing archive. */
+          if (! IS_ABSOLUTE_PATH (filename)
+              && ! IS_ABSOLUTE_PATH (abfd->filename))
+            normal = adjust_relative_path (filename, abfd->filename);
+          else
+            normal = filename;
+
+          /* In a thin archive, always store the full pathname
+             in the extended name table.  */
+          total_namelen += strlen (normal) + 1;
+         if (trailing_slash)
+           /* Leave room for trailing slash.  */
+           ++total_namelen;
+
+          continue;
+        }
+
       normal = normalize (current, current->filename);
       if (normal == NULL)
        return FALSE;
@@ -1290,38 +1512,85 @@ _bfd_construct_extended_name_table (bfd *abfd,
   *tablen = total_namelen;
   strptr = *tabloc;
 
+  last_filename = NULL;
+  last_stroff = 0;
+
   for (current = abfd->archive_head;
        current != NULL;
        current = current->archive_next)
     {
       const char *normal;
       unsigned int thislen;
-
-      normal = normalize (current, current->filename);
-      if (normal == NULL)
-       return FALSE;
+      long stroff;
+      const char *filename = current->filename;
+
+      if (bfd_is_thin_archive (abfd))
+        {
+          /* If the element being added is a member of another archive
+             (i.e., we are flattening), use the containing archive's name.  */
+          if (current->my_archive
+              && ! bfd_is_thin_archive (current->my_archive))
+            filename = current->my_archive->filename;
+          /* If the path is the same as the previous path seen,
+             reuse it.  This can happen when flattening a thin
+             archive that contains other archives.
+             If the path is relative, adjust it relative to
+             the containing archive.  */
+          if (last_filename && strcmp (last_filename, filename) == 0)
+            normal = last_filename;
+          else if (! IS_ABSOLUTE_PATH (filename)
+                   && ! IS_ABSOLUTE_PATH (abfd->filename))
+            normal = adjust_relative_path (filename, abfd->filename);
+          else
+            normal = filename;
+        }
+      else
+        {
+          normal = normalize (current, filename);
+          if (normal == NULL)
+            return FALSE;
+        }
 
       thislen = strlen (normal);
-      if (thislen > maxname)
+      if (thislen > maxname || bfd_is_thin_archive (abfd))
        {
          /* Works for now; may need to be re-engineered if we
             encounter an oddball archive format and want to
             generalise this hack.  */
          struct ar_hdr *hdr = arch_hdr (current);
-         strcpy (strptr, normal);
-         if (! trailing_slash)
-           strptr[thislen] = '\012';
-         else
-           {
-             strptr[thislen] = '/';
-             strptr[thislen + 1] = '\012';
+         if (normal == last_filename)
+           stroff = last_stroff;
+          else
+            {
+             strcpy (strptr, normal);
+             if (! trailing_slash)
+               strptr[thislen] = ARFMAG[0];
+             else
+               {
+                 strptr[thislen] = '/';
+                 strptr[thislen + 1] = ARFMAG[0];
+               }
+             stroff = strptr - *tabloc;
+             last_stroff = stroff;
            }
          hdr->ar_name[0] = ar_padchar (current);
-          _bfd_ar_spacepad (hdr->ar_name + 1, maxname - 1, "%-ld",
-                            strptr - *tabloc);
-         strptr += thislen + 1;
-         if (trailing_slash)
-           ++strptr;
+         if (bfd_is_thin_archive (abfd) && current->origin > 0)
+           {
+             int len = snprintf (hdr->ar_name + 1, maxname - 1, "%-ld:",
+                                 stroff);
+             _bfd_ar_spacepad (hdr->ar_name + 1 + len, maxname - 1 - len,
+                                "%-ld",
+                                current->origin - sizeof (struct ar_hdr));
+           }
+         else
+            _bfd_ar_spacepad (hdr->ar_name + 1, maxname - 1, "%-ld", stroff);
+          if (normal != last_filename)
+            {
+             strptr += thislen + 1;
+             if (trailing_slash)
+               ++strptr;
+              last_filename = filename;
+           }
        }
     }
 
@@ -1593,6 +1862,7 @@ bfd_gnu_truncate_arname (bfd *abfd, const char *pathname, char *arhdr)
   {
     /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
     char *bslash = strrchr (pathname, '\\');
+
     if (filename == NULL || (bslash != NULL && bslash > filename))
       filename = bslash;
     if (filename == NULL && pathname[0] != '\0' && pathname[1] == ':')
@@ -1610,7 +1880,8 @@ bfd_gnu_truncate_arname (bfd *abfd, const char *pathname, char *arhdr)
   if (length <= maxlen)
     memcpy (hdr->ar_name, filename, length);
   else
-    {                          /* pathname: meet procrustes */
+    {
+      /* pathname: meet procrustes.  */
       memcpy (hdr->ar_name, filename, maxlen);
       if ((filename[length - 2] == '.') && (filename[length - 1] == 'o'))
        {
@@ -1638,6 +1909,7 @@ _bfd_write_archive_contents (bfd *arch)
   bfd_boolean hasobjects = FALSE;
   bfd_size_type wrote;
   int tries;
+  char *armag;
 
   /* Verify the viability of all entries; if any of them live in the
      filesystem (as opposed to living in an archive open for input)
@@ -1681,7 +1953,10 @@ _bfd_write_archive_contents (bfd *arch)
 
   if (bfd_seek (arch, (file_ptr) 0, SEEK_SET) != 0)
     return FALSE;
-  wrote = bfd_bwrite (ARMAG, SARMAG, arch);
+  armag = ARMAG;
+  if (bfd_is_thin_archive (arch))
+    armag = ARMAGT;
+  wrote = bfd_bwrite (armag, SARMAG, arch);
   if (wrote != SARMAG)
     return FALSE;
 
@@ -1707,7 +1982,7 @@ _bfd_write_archive_contents (bfd *arch)
        return FALSE;
       if ((elength % 2) == 1)
        {
-         if (bfd_bwrite ("\012", 1, arch) != 1)
+         if (bfd_bwrite (ARFMAG, 1, arch) != 1)
            return FALSE;
        }
     }
@@ -1724,11 +1999,15 @@ _bfd_write_archive_contents (bfd *arch)
       if (bfd_bwrite (hdr, sizeof (*hdr), arch)
          != sizeof (*hdr))
        return FALSE;
+      if (bfd_is_thin_archive (arch))
+        continue;
       if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0)
        goto input_err;
+
       while (remaining)
        {
          unsigned int amt = DEFAULT_BUFFERSIZE;
+
          if (amt > remaining)
            amt = remaining;
          errno = 0;
@@ -1742,9 +2021,10 @@ _bfd_write_archive_contents (bfd *arch)
            return FALSE;
          remaining -= amt;
        }
+
       if ((arelt_size (current) % 2) == 1)
        {
-         if (bfd_bwrite ("\012", 1, arch) != 1)
+         if (bfd_bwrite (ARFMAG, 1, arch) != 1)
            return FALSE;
        }
     }
@@ -1809,8 +2089,8 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
     goto error_return;
 
   /* Drop all the files called __.SYMDEF, we're going to make our own.  */
-  while (arch->archive_head &&
-        strcmp (arch->archive_head->filename, "__.SYMDEF") == 0)
+  while (arch->archive_head
+        && strcmp (arch->archive_head->filename, "__.SYMDEF") == 0)
     arch->archive_head = arch->archive_head->archive_next;
 
   /* Map over each element.  */
@@ -1851,10 +2131,10 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
                  flagword flags = (syms[src_count])->flags;
                  asection *sec = syms[src_count]->section;
 
-                 if ((flags & BSF_GLOBAL ||
-                      flags & BSF_WEAK ||
-                      flags & BSF_INDIRECT ||
-                      bfd_is_com_section (sec))
+                 if ((flags & BSF_GLOBAL
+                      || flags & BSF_WEAK
+                      || flags & BSF_INDIRECT
+                      || bfd_is_com_section (sec))
                      && ! bfd_is_und_section (sec))
                    {
                      bfd_size_type namelen;
@@ -2139,10 +2419,14 @@ coff_write_armap (bfd *arch,
            return FALSE;
          count++;
        }
-      /* Add size of this archive entry.  */
-      archive_member_file_ptr += arelt_size (current) + sizeof (struct ar_hdr);
-      /* Remember aboout the even alignment.  */
-      archive_member_file_ptr += archive_member_file_ptr % 2;
+      archive_member_file_ptr += sizeof (struct ar_hdr);
+      if (! bfd_is_thin_archive (arch))
+        {
+          /* Add size of this archive entry.  */
+          archive_member_file_ptr += arelt_size (current);
+          /* Remember about the even alignment.  */
+          archive_member_file_ptr += archive_member_file_ptr % 2;
+        }
       current = current->archive_next;
     }
 
index 1c11f6bbbfcf63a580034b5f1745815f0487a9fa..319c0df7bf041ebb2d75570e41484b929b9140f1 100644 (file)
@@ -499,6 +499,7 @@ extern void warn_deprecated (const char *, const char *, int, const char *);
 #define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags)
 #define bfd_my_archive(abfd) ((abfd)->my_archive)
 #define bfd_has_map(abfd) ((abfd)->has_armap)
+#define bfd_is_thin_archive(abfd) ((abfd)->is_thin_archive)
 
 #define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types)
 #define bfd_usrdata(abfd) ((abfd)->usrdata)
index 4e13bef7d8f4cb6eb573a9f7b29caea58aeb2189..88dc337b1212155bdae3fd1c89fc81f871e03f82 100644 (file)
@@ -506,6 +506,7 @@ extern void warn_deprecated (const char *, const char *, int, const char *);
 #define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags)
 #define bfd_my_archive(abfd) ((abfd)->my_archive)
 #define bfd_has_map(abfd) ((abfd)->has_armap)
+#define bfd_is_thin_archive(abfd) ((abfd)->is_thin_archive)
 
 #define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types)
 #define bfd_usrdata(abfd) ((abfd)->usrdata)
@@ -4659,6 +4660,13 @@ struct bfd
      origin, with origin set to 0 for non archive files.  */
   ufile_ptr origin;
 
+  /* The origin in the archive of the proxy entry.  This will
+     normally be the same as origin, except for thin archives,
+     when it will contain the current offset of the proxy in the
+     thin archive rather than the offset of the bfd in its actual
+     container.  */
+  ufile_ptr proxy_origin;
+
   /* A hash table for section names.  */
   struct bfd_hash_table section_htab;
 
@@ -4692,6 +4700,8 @@ struct bfd
   struct bfd *my_archive;      /* The containing archive BFD.  */
   struct bfd *archive_next;    /* The next BFD in the archive.  */
   struct bfd *archive_head;    /* The first BFD in the archive.  */
+  struct bfd *nested_archives; /* List of nested archive in a flattened
+                                  thin archive.  */
 
   /* A chain of BFD structures involved in a link.  */
   struct bfd *link_next;
@@ -4774,6 +4784,9 @@ struct bfd
 
   /* Have archive map.  */
   unsigned int has_armap : 1;
+
+  /* Set if this is a thin archive.  */
+  unsigned int is_thin_archive : 1;
 };
 
 typedef enum bfd_error
index ce7b3918d678150f2861f5bd2e1b6fe2c24fc869..7e6e872feb51941aa7ae71f356f2e509e384295f 100644 (file)
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -150,6 +150,13 @@ CODE_FRAGMENT
 .     origin, with origin set to 0 for non archive files.  *}
 .  ufile_ptr origin;
 .
+.  {* The origin in the archive of the proxy entry.  This will
+.     normally be the same as origin, except for thin archives,
+.     when it will contain the current offset of the proxy in the
+.     thin archive rather than the offset of the bfd in its actual
+.     container.  *}
+.  ufile_ptr proxy_origin;
+.
 .  {* A hash table for section names.  *}
 .  struct bfd_hash_table section_htab;
 .
@@ -183,6 +190,8 @@ CODE_FRAGMENT
 .  struct bfd *my_archive;      {* The containing archive BFD.  *}
 .  struct bfd *archive_next;    {* The next BFD in the archive.  *}
 .  struct bfd *archive_head;    {* The first BFD in the archive.  *}
+.  struct bfd *nested_archives; {* List of nested archive in a flattened
+.                                  thin archive.  *}
 .
 .  {* A chain of BFD structures involved in a link.  *}
 .  struct bfd *link_next;
@@ -265,6 +274,9 @@ CODE_FRAGMENT
 .
 .  {* Have archive map.  *}
 .  unsigned int has_armap : 1;
+.
+.  {* Set if this is a thin archive.  *}
+.  unsigned int is_thin_archive : 1;
 .};
 .
 */
index f57d450a4fb8c07ca9a340c30f586e009fa47fff..949a2d2dc7494d7bba35957cc0319a5b21c0f72d 100644 (file)
@@ -91,6 +91,7 @@ struct areltdata {
   char * arch_header;          /* it's actually a string */
   unsigned int parsed_size;    /* octets of filesize not including ar_hdr */
   char *filename;              /* null-terminated */
+  file_ptr origin;             /* for element of a thin archive */
 };
 
 #define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size)
index cfc364f2435fc9bca9a538387363572fac11ea3a..1b447204dd41695bc5c17b61dee73816345b1718 100644 (file)
@@ -96,6 +96,7 @@ struct areltdata {
   char * arch_header;          /* it's actually a string */
   unsigned int parsed_size;    /* octets of filesize not including ar_hdr */
   char *filename;              /* null-terminated */
+  file_ptr origin;             /* for element of a thin archive */
 };
 
 #define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size)
index 47fef7036a22093a301d3ecc2a5ee0c13548653c..2ceb77eb21aa8417c0ea992eed77906728d3d0bf 100644 (file)
@@ -647,6 +647,8 @@ bfd_boolean
 bfd_close (bfd *abfd)
 {
   bfd_boolean ret;
+  bfd *nbfd;
+  bfd *next;
 
   if (bfd_write_p (abfd))
     {
@@ -654,6 +656,13 @@ bfd_close (bfd *abfd)
        return FALSE;
     }
 
+  /* Close nested archives (if this bfd is a thin archive).  */
+  for (nbfd = abfd->nested_archives; nbfd; nbfd = next)
+    {
+      next = nbfd->archive_next;
+      bfd_close (nbfd);
+    }
+
   if (! BFD_SEND (abfd, _close_and_cleanup, (abfd)))
     return FALSE;
 
index 30466fe5053cfad4c2528b94c129ede4de1676a1..b0e140a45429186579908ceb64563539a152e429 100644 (file)
@@ -1,3 +1,25 @@
+2008-03-27  Cary Coutant <ccoutant@google.com>
+
+        Add support for thin archives.
+       * ar.c (make_thin_archive): New global flag.
+       (map_over_members): Deal with full pathnames in thin archives.
+       (usage, main): Add 'T' option for building thin archives.
+       (replace_members): Pass thin archive flag to ar_emul_append.
+       * arsup.c (ar_open): Initialize new flag.
+       * binemul.c (ar_emul_append): Add new parameter for
+       flattening nested archives.
+       (do_ar_emul_default_append): New function.
+       (ar_emul_default_append): Factored out recursive code.
+       * binutils/binemul.h (ar_emul_default_append): Add new parameter.
+       (struct bin_emulation_xfer_struct): New parameter for ar_append.
+       * dlltool.c (gen_lib_file): Initialize thin archive flag.
+       * emul_aix.c (ar_emul_aix_internal): Add new flatten
+       parameter, currently unimplemented.
+       All callers changed.
+       * objcopy.c (copy_archive): Preserve thin archive flag.
+       * doc/binutils.texi: Update ar documentation.
+       * NEWS: Mention the new feature.
+
 2008-03-20  H.J. Lu  <hongjiu.lu@intel.com>
 
        * readelf.c (process_mips_specific): Declare addr_size as int.
index a4d24332811b94ca2d7e4cdbdc09351e95476862..ab836decb36c4ea83705eb965118b2b79b9e10b8 100644 (file)
@@ -1,4 +1,9 @@
 -*- text -*-
+* Added support for "thin" archives which contain pathnames pointing to
+  object files rather than the files themselves and which contain a
+  flattened symbol index for all objects, and archives, which have been
+  added to the archive.
+  
 * Added -F switch to objdump to include file offsets in the disassembly.
 
 * Added -c switch to readelf to allow string dumps of archive symbol index.
index 10e88890f99ca2ee85e767fd1adb3b86e929252f..71f4d734612e203f00ad4c40d76d034529c478fd 100644 (file)
@@ -40,9 +40,9 @@
 #include <sys/stat.h>
 
 #ifdef __GO32___
-#define EXT_NAME_LEN 3         /* bufflen of addition to name if it's MS-DOS */
+#define EXT_NAME_LEN 3         /* Bufflen of addition to name if it's MS-DOS.  */
 #else
-#define EXT_NAME_LEN 6         /* ditto for *NIX */
+#define EXT_NAME_LEN 6         /* Ditto for *NIX.  */
 #endif
 
 /* We need to open files in binary modes on system where that makes a
 #define O_BINARY 0
 #endif
 
-/* Kludge declaration from BFD!  This is ugly!  FIXME!  XXX */
+/* Kludge declaration from BFD!  This is ugly!  FIXME!  XXX  */
 
 struct ar_hdr *
   bfd_special_undocumented_glue (bfd * abfd, const char *filename);
 
-/* Static declarations */
+/* Static declarations */
 
 static void mri_emul (void);
 static const char *normalize (const char *, bfd *);
@@ -74,7 +74,7 @@ static int  ranlib_only (const char *archname);
 static int  ranlib_touch (const char *archname);
 static void usage (int);
 \f
-/** Globals and flags */
+/** Globals and flags */
 
 static int mri_mode;
 
@@ -134,6 +134,9 @@ static bfd_boolean ar_truncate = FALSE;
    program.  */
 static bfd_boolean full_pathname = FALSE;
 
+/* Whether to create a "thin" archive (symbol index only -- no files).  */
+static bfd_boolean make_thin_archive = FALSE;
+
 int interactive = 0;
 
 static void
@@ -176,16 +179,25 @@ map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count)
       match_count = 0;
       for (head = arch->archive_next; head; head = head->archive_next)
        {
+         const char * filename;
+
          PROGRESS (1);
-         if (head->filename == NULL)
+         filename = head->filename;
+         if (filename == NULL)
            {
              /* Some archive formats don't get the filenames filled in
                 until the elements are opened.  */
              struct stat buf;
              bfd_stat_arch_elt (head, &buf);
            }
-         if ((head->filename != NULL) &&
-             (!FILENAME_CMP (normalize (*files, arch), head->filename)))
+         else if (bfd_is_thin_archive (arch))
+           {
+             /* Thin archives store full pathnames.  Need to normalize.  */
+             filename = normalize (filename, arch);
+           }
+
+         if ((filename != NULL) &&
+             (!FILENAME_CMP (normalize (*files, arch), filename)))
            {
              ++match_count;
              if (counted_name_mode
@@ -200,6 +212,7 @@ map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count)
              function (head);
            }
        }
+
       if (!found)
        /* xgettext:c-format */
        fprintf (stderr, _("no entry %s in archive\n"), *files);
@@ -242,10 +255,11 @@ usage (int help)
       fprintf (s, _("  [c]          - do not warn if the library had to be created\n"));
       fprintf (s, _("  [s]          - create an archive index (cf. ranlib)\n"));
       fprintf (s, _("  [S]          - do not build a symbol table\n"));
+      fprintf (s, _("  [T]          - make a thin archive\n"));
       fprintf (s, _("  [v]          - be verbose\n"));
       fprintf (s, _("  [V]          - display the version number\n"));
       fprintf (s, _("  @<file>      - read options from <file>\n"));
+
       ar_emul_usage (s);
     }
   else
@@ -284,6 +298,7 @@ normalize (const char *file, bfd *abfd)
   {
     /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
     char *bslash = strrchr (file, '\\');
+
     if (filename == NULL || (bslash != NULL && bslash > filename))
       filename = bslash;
     if (filename == NULL && file[0] != '\0' && file[1] == ':')
@@ -302,7 +317,7 @@ normalize (const char *file, bfd *abfd)
       char *s;
 
       /* Space leak.  */
-      s = (char *) xmalloc (abfd->xvec->ar_max_namelen + 1);
+      s = xmalloc (abfd->xvec->ar_max_namelen + 1);
       memcpy (s, filename, abfd->xvec->ar_max_namelen);
       s[abfd->xvec->ar_max_namelen] = '\0';
       filename = s;
@@ -376,6 +391,7 @@ main (int argc, char **argv)
       {
        /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
        char *bslash = strrchr (program_name, '\\');
+
        if (temp == NULL || (bslash != NULL && bslash > temp))
          temp = bslash;
        if (temp == NULL && program_name[0] != '\0' && program_name[1] == ':')
@@ -559,6 +575,9 @@ main (int argc, char **argv)
            case 'P':
              full_pathname = TRUE;
              break;
+           case 'T':
+             make_thin_archive = TRUE;
+             break;
            default:
              /* xgettext:c-format */
              non_fatal (_("illegal option -- %c"), c);
@@ -629,6 +648,9 @@ main (int argc, char **argv)
       arch = open_inarch (inarch_filename,
                          files == NULL ? (char *) NULL : files[0]);
 
+      if (operation == extract && bfd_is_thin_archive (arch))
+       fatal (_("`x' cannot be used on thin archives."));
+
       switch (operation)
        {
        case print_table:
@@ -933,7 +955,7 @@ write_archive (bfd *iarch)
 
   if (new_name == NULL)
     bfd_fatal ("could not create temporary file whilst writing archive");
-  
+
   output_filename = new_name;
 
   obfd = bfd_openw (new_name, bfd_get_target (iarch));
@@ -956,6 +978,9 @@ write_archive (bfd *iarch)
       obfd->flags |= BFD_TRADITIONAL_FORMAT;
     }
 
+  if (make_thin_archive || bfd_is_thin_archive (iarch))
+    bfd_is_thin_archive (obfd) = 1;
+
   if (!bfd_set_archive_head (obfd, contents_head))
     bfd_fatal (old_name);
 
@@ -1189,7 +1214,8 @@ replace_members (bfd *arch, char **files_to_move, bfd_boolean quick)
       /* Add to the end of the archive.  */
       after_bfd = get_pos_bfd (&arch->archive_next, pos_end, NULL);
 
-      if (ar_emul_append (after_bfd, *files_to_move, verbose))
+      if (ar_emul_append (after_bfd, *files_to_move, verbose,
+                          make_thin_archive))
        changed = TRUE;
 
     next_file:;
index 49961b0ef1167336f5c475891d13dd55b4fe1de5..f7138eb88ed532b852054ff6a802d38e490c208b 100644 (file)
@@ -1,6 +1,6 @@
 /* arsup.c - Archive support for MRI compatibility
    Copyright 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003,
-   2004, 2007 Free Software Foundation, Inc.
+   2004, 2007, 2008 Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
 
@@ -207,6 +207,7 @@ ar_open (char *name, int t)
       bfd_set_format (obfd, bfd_archive);
 
       obfd->has_armap = 1;
+      obfd->is_thin_archive = 0;
     }
 }
 
index 0eb1c816c1aeddd8d30ad89f9bb2c9db5c5202ff..74e5d9c38497d8e928c9d293af85b9440dd01b6c 100644 (file)
@@ -1,5 +1,5 @@
 /* Binutils emulation layer.
-   Copyright 2002, 2003, 2007 Free Software Foundation, Inc.
+   Copyright 2002, 2003, 2007, 2008 Free Software Foundation, Inc.
    Written by Tom Rix, Red Hat Inc.
 
    This file is part of GNU Binutils.
@@ -39,29 +39,58 @@ ar_emul_default_usage (FILE *fp)
 }
 
 bfd_boolean
-ar_emul_append (bfd **after_bfd, char *file_name, bfd_boolean verbose)
+ar_emul_append (bfd **after_bfd, char *file_name, bfd_boolean verbose,
+                bfd_boolean flatten)
 {
   if (bin_dummy_emulation.ar_append)
-    return bin_dummy_emulation.ar_append (after_bfd, file_name, verbose);
+    return bin_dummy_emulation.ar_append (after_bfd, file_name, verbose,
+                                          flatten);
 
   return FALSE;
 }
 
+static bfd_boolean
+do_ar_emul_default_append (bfd **after_bfd, bfd *new_bfd,
+                       bfd_boolean verbose, bfd_boolean flatten)
+  {
+  /* When flattening, add the members of an archive instead of the
+     archive itself.  */
+  if (flatten && bfd_check_format (new_bfd, bfd_archive))
+    {
+      bfd *elt;
+      bfd_boolean added = FALSE;
+
+      for (elt = bfd_openr_next_archived_file (new_bfd, NULL);
+           elt;
+           elt = bfd_openr_next_archived_file (new_bfd, elt))
+        {
+          if (do_ar_emul_default_append (after_bfd, elt, verbose, TRUE))
+            {
+              added = TRUE;
+              after_bfd = &((*after_bfd)->archive_next);
+            }
+        }
+
+      return added;
+    }
+
+  AR_EMUL_APPEND_PRINT_VERBOSE (verbose, new_bfd->filename);
+
+  new_bfd->archive_next = *after_bfd;
+  *after_bfd = new_bfd;
+
+  return TRUE;
+}
+
 bfd_boolean
 ar_emul_default_append (bfd **after_bfd, char *file_name,
-                       bfd_boolean verbose)
+                       bfd_boolean verbose, bfd_boolean flatten)
 {
-  bfd *temp;
+  bfd *new_bfd;
 
-  temp = *after_bfd;
-  *after_bfd = bfd_openr (file_name, NULL);
-
-  AR_EMUL_ELEMENT_CHECK (*after_bfd, file_name);
-  AR_EMUL_APPEND_PRINT_VERBOSE (verbose, file_name);
-
-  (*after_bfd)->archive_next = temp;
-
-  return TRUE;
+  new_bfd = bfd_openr (file_name, NULL);
+  AR_EMUL_ELEMENT_CHECK (new_bfd, file_name);
+  return do_ar_emul_default_append (after_bfd, new_bfd, verbose, flatten);
 }
 
 bfd_boolean
index 4da6693267eb32f5381327db993f63715b03c93e..e2a1280f9e47b701e983de1ae72bf47874b470bc 100644 (file)
@@ -1,5 +1,5 @@
 /* Binutils emulation layer.
-   Copyright 2002, 2003, 2007 Free Software Foundation, Inc.
+   Copyright 2002, 2003, 2007, 2008 Free Software Foundation, Inc.
    Written by Tom Rix, Red Hat Inc.
 
    This file is part of GNU Binutils.
@@ -28,8 +28,9 @@
 
 extern void ar_emul_usage (FILE *);
 extern void ar_emul_default_usage (FILE *);
-extern bfd_boolean ar_emul_append (bfd **, char *, bfd_boolean);
-extern bfd_boolean ar_emul_default_append (bfd **, char *, bfd_boolean);
+extern bfd_boolean ar_emul_append (bfd **, char *, bfd_boolean, bfd_boolean);
+extern bfd_boolean ar_emul_default_append (bfd **, char *, bfd_boolean,
+                                           bfd_boolean);
 extern bfd_boolean ar_emul_replace (bfd **, char *, bfd_boolean);
 extern bfd_boolean ar_emul_default_replace (bfd **, char *, bfd_boolean);
 extern bfd_boolean ar_emul_parse_arg (char *);
@@ -54,7 +55,7 @@ typedef struct bin_emulation_xfer_struct
 {
   /* Print out the extra options.  */
   void (* ar_usage) (FILE *fp);
-  bfd_boolean (* ar_append) (bfd **, char *, bfd_boolean);
+  bfd_boolean (* ar_append) (bfd **, char *, bfd_boolean, bfd_boolean);
   bfd_boolean (* ar_replace) (bfd **, char *, bfd_boolean);
   bfd_boolean (* ar_parse_arg) (char *);
 }
index cbdde7c6d426d89ab09d58c1919a38d4f759daa5..61361b74a3df0749aa0067a7dc366880d5586205 100644 (file)
@@ -2813,6 +2813,7 @@ gen_lib_file (void)
 
   bfd_set_format (outarch, bfd_archive);
   outarch->has_armap = 1;
+  outarch->is_thin_archive = 0;
 
   /* Work out a reasonable size of things to put onto one line.  */
   ar_head = make_head ();
index 723c3a38b2d720ee4c935d5f2128ec07e53691ac..44c18dc343462ddcb65cb076527711830a551a1b 100644 (file)
@@ -211,6 +211,18 @@ You may use @samp{nm -s} or @samp{nm --print-armap} to list this index
 table.  If an archive lacks the table, another form of @command{ar} called
 @command{ranlib} can be used to add just the table.
 
+@cindex thin archives
+@sc{gnu} @command{ar} can optionally create a @emph{thin} archive,
+which contains a symbol index and references to the original copies
+of the member files of the archives.  Such an archive is useful
+for building libraries for use within a local build, where the
+relocatable objects are expected to remain available, and copying the
+contents of each object would only waste time and space.  Thin archives
+are also @emph{flattened}, so that adding one or more archives to a
+thin archive will add the elements of the nested archive individually.
+The paths to the elements of the archive are stored relative to the
+archive itself.
+
 @cindex compatibility, @command{ar}
 @cindex @command{ar} compatibility
 @sc{gnu} @command{ar} is designed to be compatible with two different
@@ -356,6 +368,8 @@ use the @samp{v} modifier with this operation, to request that
 If you do not specify a @var{member}, all files in the archive
 are extracted.
 
+Files cannot be extracted from a thin archive.
+
 @end table
 
 A number of modifiers (@var{mod}) may immediately follow the @var{p}
@@ -434,6 +448,12 @@ with the linker.  In order to build a symbol table, you must omit the
 @samp{S} modifier on the last execution of @samp{ar}, or you must run
 @samp{ranlib} on the archive.
 
+@item T
+@cindex creating thin archive
+Make the specified @var{archive} a @emph{thin} archive.  If it already
+exists and is a regular archive, the existing members must be present
+in the same directory as @var{archive}.
+
 @item u
 @cindex updating an archive
 Normally, @samp{ar r}@dots{} inserts all files
index 22ff8300479f1dc982527c77758e84f00fc08369..d68a5ec0b50c64b7a6a1fd60e51520486cfcd099 100644 (file)
@@ -1,5 +1,5 @@
 /* Binutils emulation layer.
-   Copyright 2002, 2003, 2006, 2007 Free Software Foundation, Inc.
+   Copyright 2002, 2003, 2006, 2007, 2008 Free Software Foundation, Inc.
    Written by Tom Rix, Red Hat Inc.
 
    This file is part of GNU Binutils.
@@ -35,15 +35,6 @@ static bfd_boolean X32 = TRUE;
 /* Whether to include 64 bit objects.  */
 static bfd_boolean X64 = FALSE;
 
-static void ar_emul_aix_usage (FILE *);
-static bfd_boolean ar_emul_aix_append (bfd **, char *, bfd_boolean);
-static bfd_boolean ar_emul_aix5_append (bfd **, char *, bfd_boolean);
-static bfd_boolean ar_emul_aix_replace (bfd **, char *, bfd_boolean);
-static bfd_boolean ar_emul_aix5_replace (bfd **, char *, bfd_boolean);
-static bfd_boolean ar_emul_aix_parse_arg (char *);
-static bfd_boolean ar_emul_aix_internal
-  (bfd **, char *, bfd_boolean, const char *, bfd_boolean);
-
 static void
 ar_emul_aix_usage (FILE *fp)
 {
@@ -56,8 +47,12 @@ ar_emul_aix_usage (FILE *fp)
 }
 
 static bfd_boolean
-ar_emul_aix_internal (bfd **after_bfd, char *file_name, bfd_boolean verbose,
-                     const char * target_name, bfd_boolean is_append)
+ar_emul_aix_internal (bfd **       after_bfd,
+                     char *       file_name,
+                     bfd_boolean  verbose,
+                     const char * target_name,
+                     bfd_boolean  is_append,
+                     bfd_boolean  flatten ATTRIBUTE_UNUSED)
 {
   bfd *temp;
   bfd *try_bfd;
@@ -97,31 +92,33 @@ ar_emul_aix_internal (bfd **after_bfd, char *file_name, bfd_boolean verbose,
 
 
 static bfd_boolean
-ar_emul_aix_append (bfd **after_bfd, char *file_name, bfd_boolean verbose)
+ar_emul_aix_append (bfd **after_bfd, char *file_name, bfd_boolean verbose,
+                    bfd_boolean flatten)
 {
   return ar_emul_aix_internal (after_bfd, file_name, verbose,
-                              "aixcoff64-rs6000", TRUE);
+                              "aixcoff64-rs6000", TRUE, flatten);
 }
 
 static bfd_boolean
-ar_emul_aix5_append (bfd **after_bfd, char *file_name, bfd_boolean verbose)
+ar_emul_aix5_append (bfd **after_bfd, char *file_name, bfd_boolean verbose,
+                     bfd_boolean flatten)
 {
   return ar_emul_aix_internal (after_bfd, file_name, verbose,
-                              "aix5coff64-rs6000", TRUE);
+                              "aix5coff64-rs6000", TRUE, flatten);
 }
 
 static bfd_boolean
 ar_emul_aix_replace (bfd **after_bfd, char *file_name, bfd_boolean verbose)
 {
   return ar_emul_aix_internal (after_bfd, file_name, verbose,
-                              "aixcoff64-rs6000", FALSE);
+                              "aixcoff64-rs6000", FALSE, FALSE);
 }
 
 static bfd_boolean
 ar_emul_aix5_replace (bfd **after_bfd, char *file_name, bfd_boolean verbose)
 {
   return ar_emul_aix_internal (after_bfd, file_name, verbose,
-                              "aix5coff64-rs6000", FALSE);
+                              "aix5coff64-rs6000", FALSE, FALSE);
 }
 
 static bfd_boolean
index b89de4656193cbb458483eed4995b2f64515d14f..1dd36114e908fc95733702d73fa4cd87adff8bd4 100644 (file)
@@ -1,6 +1,6 @@
 /* objcopy.c -- copy object file from input to output, optionally massaging it.
    Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007
+   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
@@ -1830,6 +1830,7 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
           strerror (errno));
 
   obfd->has_armap = ibfd->has_armap;
+  obfd->is_thin_archive = ibfd->is_thin_archive;
 
   list = NULL;
 
index ac5be6d0c6455c6a9558fc459bb14838b55c7937..e7cc69ace14b0aa2a6994e72cbbe833494424554 100644 (file)
@@ -1,3 +1,7 @@
+2008-03-27  Cary Coutant <ccoutant@google.com>
+
+       * binutils-all/ar.exp: Add thin archive tests.
+
 2008-02-26  Joseph Myers  <joseph@codesourcery.com>
 
        * config/default.exp (gcc_gas_flag, dlltool_gas_flag): Define to
index 67504c3f72a23ddea17815a97511bb30d8ffe5e8..21a39f48ea6e003a339e4d729d71488a3a7cc9a1 100644 (file)
@@ -1,4 +1,4 @@
-#   Copyright 1995, 1997, 2002, 2004, 2007 Free Software Foundation, Inc.
+#   Copyright 1995, 1997, 2002, 2004, 2007, 2008 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -215,6 +215,110 @@ proc symbol_table { } {
     pass $testname
 }
 
+# Test building a thin archive.
+
+proc thin_archive { } {
+    global AR
+    global AS
+    global NM
+    global srcdir
+    global subdir
+
+    set testname "ar thin archive"
+
+    if ![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.o] {
+       unresolved $testname
+       return
+    }
+
+    if [is_remote host] {
+       set archive artest.a
+       set objfile [remote_download host tmpdir/bintest.o]
+       remote_file host delete $archive
+    } else {
+       set archive tmpdir/artest.a
+       set objfile tmpdir/bintest.o
+    }
+
+    remote_file build delete tmpdir/artest.a
+
+    set got [binutils_run $AR "rcT $archive ${objfile}"]
+    if ![string match "" $got] {
+       fail $testname
+       return
+    }
+
+    set got [binutils_run $NM "--print-armap $archive"]
+    if { ![string match "*text_symbol in *bintest.o*" $got] \
+        || ![string match "*data_symbol in *bintest.o*" $got] \
+        || ![string match "*common_symbol in *bintest.o*" $got] \
+        || [string match "*static_text_symbol in *bintest.o*" $got] \
+        || [string match "*static_data_symbol in *bintest.o*" $got] \
+        || [string match "*external_symbol in *bintest.o*" $got] } {
+       fail $testname
+       return
+    }
+
+    pass $testname
+}
+
+# Test building a thin archive with a nested archive.
+
+proc thin_archive_with_nested { } {
+    global AR
+    global AS
+    global NM
+    global srcdir
+    global subdir
+
+    set testname "ar thin archive with nested archive"
+
+    if ![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.o] {
+       unresolved $testname
+       return
+    }
+
+    if [is_remote host] {
+       set archive artest.a
+       set archive2 artest2.a
+       set objfile [remote_download host tmpdir/bintest.o]
+       remote_file host delete $archive
+    } else {
+       set archive tmpdir/artest.a
+       set archive2 tmpdir/artest2.a
+       set objfile tmpdir/bintest.o
+    }
+
+    remote_file build delete tmpdir/artest.a
+
+    set got [binutils_run $AR "rc $archive ${objfile}"]
+    if ![string match "" $got] {
+       fail $testname
+       return
+    }
+
+    remote_file build delete tmpdir/artest2.a
+
+    set got [binutils_run $AR "rcT $archive2 ${archive}"]
+    if ![string match "" $got] {
+       fail $testname
+       return
+    }
+
+    set got [binutils_run $NM "--print-armap $archive"]
+    if { ![string match "*text_symbol in *bintest.o*" $got] \
+        || ![string match "*data_symbol in *bintest.o*" $got] \
+        || ![string match "*common_symbol in *bintest.o*" $got] \
+        || [string match "*static_text_symbol in *bintest.o*" $got] \
+        || [string match "*static_data_symbol in *bintest.o*" $got] \
+        || [string match "*external_symbol in *bintest.o*" $got] } {
+       fail $testname
+       return
+    }
+
+    pass $testname
+}
+
 # Test POSIX-compatible argument parsing.
 
 proc argument_parsing { } {
@@ -254,4 +358,6 @@ proc argument_parsing { } {
 
 long_filenames
 symbol_table
+thin_archive
+thin_archive_with_nested
 argument_parsing
index e00c698c3cc04b24f0e9f425078fd61f9bf3ec6e..6d1f374e2c939b3243acd9b43ea2e07177c14817 100644 (file)
@@ -1,3 +1,7 @@
+2008-03-27  Cary Coutant <ccoutant@google.com>
+
+       * ar.h (ARMAGT): New magic string for thin archives.
+
 2005-05-10  Nick Clifton  <nickc@redhat.com>
 
        * Update the address and phone number of the FSF organization in
index 0d0aad2d5e3de70dde4586158de92c6662bef8c5..7b77997915bfb92c5b33e2bda0678b216d40e027 100644 (file)
@@ -1,6 +1,6 @@
 /* archive file definition for GNU software
 
-   Copyright 2001 Free Software Foundation, Inc.
+   Copyright 2001, 2008 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -26,8 +26,9 @@
    characters, as allowed by ANSI.  '\012' has a fixed value, and remains
    compatible with existing BSDish archives. */
 
-#define ARMAG  "!<arch>\012"   /* For COFF and a.out archives */
-#define ARMAGB "!<bout>\012"   /* For b.out archives */
+#define ARMAG  "!<arch>\012"   /* For COFF and a.out archives.  */
+#define ARMAGB "!<bout>\012"   /* For b.out archives.  */
+#define ARMAGT "!<thin>\012"   /* For thin archives.  */
 #define SARMAG 8
 #define ARFMAG "`\012"
 
 
 #define ARMAP_TIME_OFFSET       60
 
-struct ar_hdr {
-  char ar_name[16];            /* name of this member */
-  char ar_date[12];            /* file mtime */
-  char ar_uid[6];              /* owner uid; printed as decimal */
-  char ar_gid[6];              /* owner gid; printed as decimal */
-  char ar_mode[8];             /* file mode, printed as octal   */
-  char ar_size[10];            /* file size, printed as decimal */
-  char ar_fmag[2];             /* should contain ARFMAG */
+struct ar_hdr
+{
+  char ar_name[16];            /* Name of this member.  */
+  char ar_date[12];            /* File mtime.  */
+  char ar_uid[6];              /* Owner uid; printed as decimal.  */
+  char ar_gid[6];              /* Owner gid; printed as decimal.  */
+  char ar_mode[8];             /* File mode, printed as octal.   */
+  char ar_size[10];            /* File size, printed as decimal.  */
+  char ar_fmag[2];             /* Should contain ARFMAG.  */
 };
 
 #endif /* __GNU_AR_H__ */