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 55514b4..063a304 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
 2008-03-25  Bernd Schmidt  <bernd.schmidt@analog.com>
 
        * elf32-bfin.c (bfin_final_link_relocate): New function, wrapper around
index e080d3a..5389f7a 100644 (file)
@@ -1,6 +1,6 @@
 /* BFD back-end for archive files (libraries).
    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
 /* 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.
 
    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 "aout/ranlib.h"
 #include "safe-ctype.h"
 #include "hashtab.h"
+#include "filenames.h"
 
 #ifndef errno
 extern int errno;
 
 #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 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)
 \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
   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 *
 /* 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;
 {
   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.  */
 
   /* 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;
     }
   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;
 }
 
   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;
   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))
     {
 
   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)
     {
           && 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;
     }
       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->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;
 
   if (filename != NULL)
     ared->filename = filename;
@@ -491,6 +531,30 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag)
   return ared;
 }
 \f
   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.  */
 /* 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;
 {
   struct areltdata *new_areldata;
   bfd *n_nfd;
+  char *filename;
 
   if (archive->my_archive)
     {
 
   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;
 
   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;
     }
 
   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->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?  */
 
   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;
   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)
 {
 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;
     {
       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);
   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...
       if (archive->my_archive)
        filestart -= archive->origin;
       /* Pad to an even boundary...
@@ -615,8 +735,11 @@ bfd_generic_archive_p (bfd *abfd)
       return NULL;
     }
 
       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);
     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)
          {
        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 = '/';
              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
 
 }
 #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
 /* 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;
   bfd_size_type total_namelen = 0;
   bfd *current;
   char *strptr;
+  const char *last_filename;
+  long last_stroff;
 
   *tablen = 0;
 
   *tablen = 0;
+  last_filename = NULL;
 
   /* Figure out how long the table should be.  */
   for (current = abfd->archive_head;
 
   /* 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;
 
       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;
       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;
 
   *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;
   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);
 
       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);
        {
          /* 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);
            }
          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, '\\');
   {
     /* 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] == ':')
     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
   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'))
        {
       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;
   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)
 
   /* 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;
 
   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;
 
   if (wrote != SARMAG)
     return FALSE;
 
@@ -1707,7 +1982,7 @@ _bfd_write_archive_contents (bfd *arch)
        return FALSE;
       if ((elength % 2) == 1)
        {
        return FALSE;
       if ((elength % 2) == 1)
        {
-         if (bfd_bwrite ("\012", 1, arch) != 1)
+         if (bfd_bwrite (ARFMAG, 1, arch) != 1)
            return FALSE;
        }
     }
            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_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;
       if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0)
        goto input_err;
+
       while (remaining)
        {
          unsigned int amt = DEFAULT_BUFFERSIZE;
       while (remaining)
        {
          unsigned int amt = DEFAULT_BUFFERSIZE;
+
          if (amt > remaining)
            amt = remaining;
          errno = 0;
          if (amt > remaining)
            amt = remaining;
          errno = 0;
@@ -1742,9 +2021,10 @@ _bfd_write_archive_contents (bfd *arch)
            return FALSE;
          remaining -= amt;
        }
            return FALSE;
          remaining -= amt;
        }
+
       if ((arelt_size (current) % 2) == 1)
        {
       if ((arelt_size (current) % 2) == 1)
        {
-         if (bfd_bwrite ("\012", 1, arch) != 1)
+         if (bfd_bwrite (ARFMAG, 1, arch) != 1)
            return FALSE;
        }
     }
            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.  */
     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.  */
     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;
 
                  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;
                      && ! bfd_is_und_section (sec))
                    {
                      bfd_size_type namelen;
@@ -2139,10 +2419,14 @@ coff_write_armap (bfd *arch,
            return FALSE;
          count++;
        }
            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;
     }
 
       current = current->archive_next;
     }
 
index 1c11f6b..319c0df 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_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)
 
 #define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types)
 #define bfd_usrdata(abfd) ((abfd)->usrdata)
index 4e13bef..88dc337 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_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)
 
 #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;
 
      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;
 
   /* 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 *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;
 
   /* 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;
 
   /* 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
 };
 
 typedef enum bfd_error
index ce7b391..7e6e872 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;
 .
 .     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;
 .
 .  {* 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 *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;
 .
 .  {* 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;
 .
 .  {* Have archive map.  *}
 .  unsigned int has_armap : 1;
+.
+.  {* Set if this is a thin archive.  *}
+.  unsigned int is_thin_archive : 1;
 .};
 .
 */
 .};
 .
 */
index f57d450..949a2d2 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 */
   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)
 };
 
 #define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size)
index cfc364f..1b44720 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 */
   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)
 };
 
 #define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size)
index 47fef70..2ceb77e 100644 (file)
@@ -647,6 +647,8 @@ bfd_boolean
 bfd_close (bfd *abfd)
 {
   bfd_boolean ret;
 bfd_close (bfd *abfd)
 {
   bfd_boolean ret;
+  bfd *nbfd;
+  bfd *next;
 
   if (bfd_write_p (abfd))
     {
 
   if (bfd_write_p (abfd))
     {
@@ -654,6 +656,13 @@ bfd_close (bfd *abfd)
        return FALSE;
     }
 
        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;
 
   if (! BFD_SEND (abfd, _close_and_cleanup, (abfd)))
     return FALSE;
 
index 30466fe..b0e140a 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.
 2008-03-20  H.J. Lu  <hongjiu.lu@intel.com>
 
        * readelf.c (process_mips_specific): Declare addr_size as int.
index a4d2433..ab836de 100644 (file)
@@ -1,4 +1,9 @@
 -*- text -*-
 -*- 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.
 * 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 10e8889..71f4d73 100644 (file)
@@ -40,9 +40,9 @@
 #include <sys/stat.h>
 
 #ifdef __GO32___
 #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
 #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
 #endif
 
 /* We need to open files in binary modes on system where that makes a
 #define O_BINARY 0
 #endif
 
 #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);
 
 
 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 *);
 
 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
 static int  ranlib_touch (const char *archname);
 static void usage (int);
 \f
-/** Globals and flags */
+/** Globals and flags */
 
 static int mri_mode;
 
 
 static int mri_mode;
 
@@ -134,6 +134,9 @@ static bfd_boolean ar_truncate = FALSE;
    program.  */
 static bfd_boolean full_pathname = 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
 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)
        {
       match_count = 0;
       for (head = arch->archive_next; head; head = head->archive_next)
        {
+         const char * filename;
+
          PROGRESS (1);
          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);
            }
            {
              /* 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
            {
              ++match_count;
              if (counted_name_mode
@@ -200,6 +212,7 @@ map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count)
              function (head);
            }
        }
              function (head);
            }
        }
+
       if (!found)
        /* xgettext:c-format */
        fprintf (stderr, _("no entry %s in archive\n"), *files);
       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, _("  [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"));
       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
       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, '\\');
   {
     /* 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] == ':')
     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.  */
       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;
       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, '\\');
       {
        /* 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] == ':')
        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 'P':
              full_pathname = TRUE;
              break;
+           case 'T':
+             make_thin_archive = TRUE;
+             break;
            default:
              /* xgettext:c-format */
              non_fatal (_("illegal option -- %c"), c);
            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]);
 
       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:
       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");
 
   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));
   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;
     }
 
       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);
 
   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);
 
       /* 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:;
        changed = TRUE;
 
     next_file:;
index 49961b0..f7138eb 100644 (file)
@@ -1,6 +1,6 @@
 /* arsup.c - Archive support for MRI compatibility
    Copyright 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003,
 /* 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.
 
 
    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;
       bfd_set_format (obfd, bfd_archive);
 
       obfd->has_armap = 1;
+      obfd->is_thin_archive = 0;
     }
 }
 
     }
 }
 
index 0eb1c81..74e5d9c 100644 (file)
@@ -1,5 +1,5 @@
 /* Binutils emulation layer.
 /* 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.
    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
 }
 
 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)
 {
   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;
 }
 
 
   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
 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
 }
 
 bfd_boolean
index 4da6693..e2a1280 100644 (file)
@@ -1,5 +1,5 @@
 /* Binutils emulation layer.
 /* 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.
    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 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 *);
 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);
 {
   /* 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 *);
 }
   bfd_boolean (* ar_replace) (bfd **, char *, bfd_boolean);
   bfd_boolean (* ar_parse_arg) (char *);
 }
index cbdde7c..61361b7 100644 (file)
@@ -2813,6 +2813,7 @@ gen_lib_file (void)
 
   bfd_set_format (outarch, bfd_archive);
   outarch->has_armap = 1;
 
   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 ();
 
   /* Work out a reasonable size of things to put onto one line.  */
   ar_head = make_head ();
index 723c3a3..44c18dc 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.
 
 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
 @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.
 
 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}
 @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.
 
 @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
 @item u
 @cindex updating an archive
 Normally, @samp{ar r}@dots{} inserts all files
index 22ff830..d68a5ec 100644 (file)
@@ -1,5 +1,5 @@
 /* Binutils emulation layer.
 /* 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.
    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;
 
 /* 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)
 {
 static void
 ar_emul_aix_usage (FILE *fp)
 {
@@ -56,8 +47,12 @@ ar_emul_aix_usage (FILE *fp)
 }
 
 static bfd_boolean
 }
 
 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;
 {
   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
 
 
 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,
 {
   return ar_emul_aix_internal (after_bfd, file_name, verbose,
-                              "aixcoff64-rs6000", TRUE);
+                              "aixcoff64-rs6000", TRUE, flatten);
 }
 
 static bfd_boolean
 }
 
 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,
 {
   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,
 }
 
 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,
 }
 
 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
 }
 
 static bfd_boolean
index b89de46..1dd3611 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,
 /* 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.
    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;
           strerror (errno));
 
   obfd->has_armap = ibfd->has_armap;
+  obfd->is_thin_archive = ibfd->is_thin_archive;
 
   list = NULL;
 
 
   list = NULL;
 
index ac5be6d..e7cc69a 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
 2008-02-26  Joseph Myers  <joseph@codesourcery.com>
 
        * config/default.exp (gcc_gas_flag, dlltool_gas_flag): Define to
index 67504c3..21a39f4 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
 
 # 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
 }
 
     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 { } {
 # Test POSIX-compatible argument parsing.
 
 proc argument_parsing { } {
@@ -254,4 +358,6 @@ proc argument_parsing { } {
 
 long_filenames
 symbol_table
 
 long_filenames
 symbol_table
+thin_archive
+thin_archive_with_nested
 argument_parsing
 argument_parsing
index e00c698..6d1f374 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
 2005-05-10  Nick Clifton  <nickc@redhat.com>
 
        * Update the address and phone number of the FSF organization in
index 0d0aad2..7b77997 100644 (file)
@@ -1,6 +1,6 @@
 /* archive file definition for GNU software
 
 /* 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
 
    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. */
 
    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 SARMAG 8
 #define ARFMAG "`\012"
 
 
 #define ARMAP_TIME_OFFSET       60
 
 
 #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__ */
 };
 
 #endif /* __GNU_AR_H__ */