Add an option to the archiver to add a section recording library dependencies.
authorHoward Chu <hyc@symas.com>
Tue, 3 Nov 2020 15:12:47 +0000 (15:12 +0000)
committerNick Clifton <nickc@redhat.com>
Tue, 3 Nov 2020 15:12:47 +0000 (15:12 +0000)
* ar.c (long_options): Add --record-libdeps.
(usage): Mention the new option.
(decode_options): Handle the new option.
(replace_members): If necessary, create a bfd to hold the libdeps
description.
* binemul.c (ar_emul_append_bfd): New function.
(ar_emul_replace_bfd): New function.
(ar_emul_default_append): Replace file_name and target arguments
with new_bfd argument.
(ar_emul_default_replace): Likewise.
* binemul.h: Update prototypes.
(struct bin_emulation_xfer_struct): Update fields.
* doc/binutils.texi: Document the new option.
* NEWS: Mention the new feature.
* emul_aix.c (ar_emul_aix_append): Update.
(ar_emul_aix_replace): Likewise.
* testsuite/binutils-all/ar.exp: Add test of new feature.

binutils/ChangeLog
binutils/NEWS
binutils/ar.c
binutils/binemul.c
binutils/binemul.h
binutils/doc/binutils.texi
binutils/emul_aix.c
binutils/testsuite/binutils-all/ar.exp

index 4ae34af492803cc3dd69fba8d27e43c674cc3409..3d6732f0eaa11de2673c117be776815255872c26 100644 (file)
@@ -1,3 +1,23 @@
+2020-11-03  Howard Chu  <hyc@symas.com>
+
+       * ar.c (long_options): Add --record-libdeps.
+       (usage): Mention the new option.
+       (decode_options): Handle the new option.
+       (replace_members): If necessary, create a bfd to hold the libdeps
+       description.
+       * binemul.c (ar_emul_append_bfd): New function.
+       (ar_emul_replace_bfd): New function.
+       (ar_emul_default_append): Replace file_name and target arguments
+       with new_bfd argument.
+       (ar_emul_default_replace): Likewise.
+       * binemul.h: Update prototypes.
+       (struct bin_emulation_xfer_struct): Update fields.
+       * doc/binutils.texi: Document the new option.
+       * NEWS: Mention the new feature.
+       * emul_aix.c (ar_emul_aix_append): Update.
+       (ar_emul_aix_replace): Likewise.
+       * testsuite/binutils-all/ar.exp: Add test of new feature.
+
 2020-10-30  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR gas/26703
index 35e4e303e15e172ade188993a2b6d875d2d0336c..02a19ea09bccda89da52039b5973a2889514713d 100644 (file)
@@ -1,5 +1,10 @@
 -*- text -*-
 
+* The ar tool's previously unused l modifier is now used for specifying
+  dependencies of a static library. The arguments of this option
+  (or --record-libdeps long form option) will be stored verbatim in the
+  __.LIBDEP member of the archive, which the linker may read at link time.
+
 * Readelf can now display the contents of LTO symbol table sections when asked
   to do so via the --lto-syms command line option.
 
index 85b342a6502768be49dd2b97362dde96957a6099..56c758cc1af010c0d9689ea870c8c8d08a937749 100644 (file)
@@ -138,6 +138,11 @@ static bfd_boolean full_pathname = FALSE;
 /* Whether to create a "thin" archive (symbol index only -- no files).  */
 static bfd_boolean make_thin_archive = FALSE;
 
+#define LIBDEPS        "__.LIBDEP"
+/* Text to store in the __.LIBDEP archive element for the linker to use.  */
+static char * libdeps = NULL;
+static bfd *  libdeps_bfd = NULL;
+
 static int show_version = 0;
 
 static int show_help = 0;
@@ -166,6 +171,7 @@ static struct option long_options[] =
   {"target", required_argument, NULL, OPTION_TARGET},
   {"version", no_argument, &show_version, 1},
   {"output", required_argument, NULL, OPTION_OUTPUT},
+  {"record-libdeps", required_argument, NULL, 'l'},
   {NULL, no_argument, NULL, 0}
 };
 
@@ -329,6 +335,7 @@ usage (int help)
   fprintf (s, _(" generic modifiers:\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, _("  [l <text> ]  - specify the dependencies of this library\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"));
@@ -336,6 +343,7 @@ usage (int help)
   fprintf (s, _("  @<file>      - read options from <file>\n"));
   fprintf (s, _("  --target=BFDNAME - specify the target object format as BFDNAME\n"));
   fprintf (s, _("  --output=DIRNAME - specify the output directory for extraction operations\n"));
+  fprintf (s, _("  --record-libdeps=<text> - specify the dependencies of this library\n"));
 #if BFD_SUPPORTS_PLUGINS
   fprintf (s, _(" optional:\n"));
   fprintf (s, _("  --plugin <p> - load the specified plugin\n"));
@@ -487,7 +495,7 @@ decode_options (int argc, char **argv)
       argv = new_argv;
     }
 
-  while ((c = getopt_long (argc, argv, "hdmpqrtxlcoOVsSuvabiMNfPTDU",
+  while ((c = getopt_long (argc, argv, "hdmpqrtxl:coOVsSuvabiMNfPTDU",
                           long_options, NULL)) != EOF)
     {
       switch (c)
@@ -535,6 +543,9 @@ decode_options (int argc, char **argv)
           operation = extract;
           break;
         case 'l':
+          if (libdeps != NULL)
+            fatal (_("libdeps specified more than once"));
+          libdeps = optarg;
           break;
         case 'c':
           silent_create = 1;
@@ -847,6 +858,49 @@ main (int argc, char **argv)
       if (operation == extract && bfd_is_thin_archive (arch))
        fatal (_("`x' cannot be used on thin archives."));
 
+      if (libdeps != NULL)
+       {
+         char **new_files;
+         bfd_size_type reclen = strlen (libdeps) + 1;
+
+         /* Create a bfd to contain the dependencies.
+            It inherits its type from arch, but we must set the type to
+            "binary" otherwise bfd_bwrite() will fail.  After writing, we
+            must set the type back to "plugin" otherwise adding it to the
+            archive will fail.  */
+         libdeps_bfd = bfd_create (LIBDEPS, arch);
+         if (libdeps_bfd == NULL)
+           fatal (_("Cannot create libdeps record."));
+
+         if (bfd_find_target ("binary", libdeps_bfd) == NULL)
+           fatal (_("Cannot set libdeps record type to binary."));
+
+         if (! bfd_set_format (libdeps_bfd, bfd_object))
+           fatal (_("Cannot set libdeps object format."));
+
+         if (! bfd_make_writable (libdeps_bfd))
+           fatal (_("Cannot make libdeps object writable."));
+
+         if (bfd_bwrite (libdeps, reclen, libdeps_bfd) != reclen)
+           fatal (_("Cannot write libdeps record."));
+
+         if (! bfd_make_readable (libdeps_bfd))
+           fatal (_("Cannot make libdeps object readable."));
+
+         if (bfd_find_target ("plugin", libdeps_bfd) == NULL)
+           fatal (_("Cannot reset libdeps record type."));
+
+         /* Append our libdeps record to the list of files
+            being operated on.  */
+         new_files = xmalloc ((file_count + 2) * sizeof (char *));
+         for (i = 0; i < file_count; i++)
+           new_files[i] = files[i];
+         new_files[i++] = LIBDEPS;
+         file_count = i;
+         files = new_files;
+         files[i] = NULL;
+       }
+
       switch (operation)
        {
        case print_table:
@@ -1432,6 +1486,7 @@ replace_members (bfd *arch, char **files_to_move, bfd_boolean quick)
                                normalize (bfd_get_filename (current), arch)) == 0
                  && current->arelt_data != NULL)
                {
+                 bfd_boolean replaced;
                  if (newer_only)
                    {
                      struct stat fsbuf, asbuf;
@@ -1453,8 +1508,19 @@ replace_members (bfd *arch, char **files_to_move, bfd_boolean quick)
 
                  after_bfd = get_pos_bfd (&arch->archive_next, pos_after,
                                           bfd_get_filename (current));
-                 if (ar_emul_replace (after_bfd, *files_to_move,
-                                      target, verbose))
+                 if (libdeps_bfd != NULL
+                     && FILENAME_CMP (normalize (*files_to_move, arch),
+                                      LIBDEPS) == 0)
+                   {
+                     replaced = ar_emul_replace_bfd (after_bfd, libdeps_bfd,
+                                                     verbose);
+                   }
+                 else
+                   {
+                     replaced = ar_emul_replace (after_bfd, *files_to_move,
+                                                 target, verbose);
+                   }
+                 if (replaced)
                    {
                      /* Snip out this entry from the chain.  */
                      *current_ptr = (*current_ptr)->archive_next;
@@ -1470,9 +1536,17 @@ 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, target,
-                         verbose, make_thin_archive))
-       changed = TRUE;
+      if (libdeps_bfd != NULL
+         && FILENAME_CMP (normalize (*files_to_move, arch), LIBDEPS) == 0)
+        {
+         changed |= ar_emul_append_bfd (after_bfd, libdeps_bfd,
+                                        verbose, make_thin_archive);
+       }
+      else
+        {
+         changed |= ar_emul_append (after_bfd, *files_to_move, target,
+                                    verbose, make_thin_archive);
+       }
 
     next_file:;
 
index 7c71b5b78c1a25116862696b7dee536f377e1c7d..8a0512ebd9b5753e3369c3d9d4bfa3da19bbc300 100644 (file)
@@ -41,9 +41,24 @@ ar_emul_default_usage (FILE *fp)
 bfd_boolean
 ar_emul_append (bfd **after_bfd, char *file_name, const char *target,
                bfd_boolean verbose, bfd_boolean flatten)
+{
+  bfd *new_bfd;
+
+  new_bfd = bfd_openr (file_name, target);
+  AR_EMUL_ELEMENT_CHECK (new_bfd, file_name);
+  if (bin_dummy_emulation.ar_append)
+    return bin_dummy_emulation.ar_append (after_bfd, new_bfd,
+                                         verbose, flatten);
+
+  return FALSE;
+}
+
+bfd_boolean
+ar_emul_append_bfd (bfd **after_bfd, bfd *new_bfd,
+               bfd_boolean verbose, bfd_boolean flatten)
 {
   if (bin_dummy_emulation.ar_append)
-    return bin_dummy_emulation.ar_append (after_bfd, file_name, target,
+    return bin_dummy_emulation.ar_append (after_bfd, new_bfd,
                                          verbose, flatten);
 
   return FALSE;
@@ -93,14 +108,9 @@ do_ar_emul_append (bfd **after_bfd, bfd *new_bfd,
 }
 
 bfd_boolean
-ar_emul_default_append (bfd **after_bfd, char *file_name,
-                       const char *target, bfd_boolean verbose,
-                       bfd_boolean flatten)
+ar_emul_default_append (bfd **after_bfd, bfd *new_bfd,
+                       bfd_boolean verbose, bfd_boolean flatten)
 {
-  bfd *new_bfd;
-
-  new_bfd = bfd_openr (file_name, target);
-  AR_EMUL_ELEMENT_CHECK (new_bfd, file_name);
   return do_ar_emul_append (after_bfd, new_bfd, verbose, flatten, any_ok);
 }
 
@@ -108,23 +118,34 @@ bfd_boolean
 ar_emul_replace (bfd **after_bfd, char *file_name, const char *target,
                 bfd_boolean verbose)
 {
+  bfd *new_bfd;
+
+  new_bfd = bfd_openr (file_name, target);
+  AR_EMUL_ELEMENT_CHECK (new_bfd, file_name);
+
   if (bin_dummy_emulation.ar_replace)
-    return bin_dummy_emulation.ar_replace (after_bfd, file_name,
-                                          target, verbose);
+    return bin_dummy_emulation.ar_replace (after_bfd, new_bfd,
+                                          verbose);
 
   return FALSE;
 }
 
 bfd_boolean
-ar_emul_default_replace (bfd **after_bfd, char *file_name,
-                        const char *target, bfd_boolean verbose)
+ar_emul_replace_bfd (bfd **after_bfd, bfd *new_bfd,
+                bfd_boolean verbose)
 {
-  bfd *new_bfd;
+  if (bin_dummy_emulation.ar_replace)
+    return bin_dummy_emulation.ar_replace (after_bfd, new_bfd,
+                                          verbose);
 
-  new_bfd = bfd_openr (file_name, target);
-  AR_EMUL_ELEMENT_CHECK (new_bfd, file_name);
+  return FALSE;
+}
 
-  AR_EMUL_REPLACE_PRINT_VERBOSE (verbose, file_name);
+bfd_boolean
+ar_emul_default_replace (bfd **after_bfd, bfd *new_bfd,
+                        bfd_boolean verbose)
+{
+  AR_EMUL_REPLACE_PRINT_VERBOSE (verbose, bfd_get_filename (new_bfd));
 
   new_bfd->archive_next = *after_bfd;
   *after_bfd = new_bfd;
index d4a14edfebe516d2981e58966c99e825e2e56603..57b2e20b7a1cfde6cb8e9abdeefbe49f1d094c4d 100644 (file)
@@ -30,15 +30,19 @@ extern void ar_emul_usage (FILE *);
 extern void ar_emul_default_usage (FILE *);
 extern bfd_boolean ar_emul_append (bfd **, char *, const char *,
                                   bfd_boolean, bfd_boolean);
-extern bfd_boolean ar_emul_default_append (bfd **, char *, const char *,
+extern bfd_boolean ar_emul_append_bfd (bfd **, bfd *,
+                                      bfd_boolean, bfd_boolean);
+extern bfd_boolean ar_emul_default_append (bfd **, bfd *,
                                           bfd_boolean, bfd_boolean);
 extern bfd_boolean do_ar_emul_append (bfd **, bfd *,
                                      bfd_boolean, bfd_boolean,
                                      bfd_boolean (*)(bfd *));
 extern bfd_boolean ar_emul_replace (bfd **, char *, const char *,
                                    bfd_boolean);
-extern bfd_boolean ar_emul_default_replace (bfd **, char *,
-                                           const char *, bfd_boolean);
+extern bfd_boolean ar_emul_replace_bfd (bfd **, bfd *,
+                                       bfd_boolean);
+extern bfd_boolean ar_emul_default_replace (bfd **, bfd *,
+                                           bfd_boolean);
 extern bfd_boolean ar_emul_parse_arg (char *);
 extern bfd_boolean ar_emul_default_parse_arg (char *);
 
@@ -61,9 +65,8 @@ typedef struct bin_emulation_xfer_struct
 {
   /* Print out the extra options.  */
   void (* ar_usage) (FILE *fp);
-  bfd_boolean (* ar_append) (bfd **, char *, const char *, bfd_boolean,
-                            bfd_boolean);
-  bfd_boolean (* ar_replace) (bfd **, char *, const char *, bfd_boolean);
+  bfd_boolean (* ar_append) (bfd **, bfd *, bfd_boolean, bfd_boolean);
+  bfd_boolean (* ar_replace) (bfd **, bfd *, bfd_boolean);
   bfd_boolean (* ar_parse_arg) (char *);
 }
 bin_emulation_xfer_type;
index 6203fde8877b8e7c5ffd38d80c94133c076a1960..41fd92a908aa7e4471daa4ecfc0e50ed0c39c3f0 100644 (file)
@@ -170,7 +170,7 @@ in the section entitled ``GNU Free Documentation License''.
 @c man title ar create, modify, and extract from archives
 
 @smallexample
-ar [-]@var{p}[@var{mod}] [@option{--plugin} @var{name}] [@option{--target} @var{bfdname}] [@option{--output} @var{dirname}] [@var{relpos}] [@var{count}] @var{archive} [@var{member}@dots{}]
+ar [-]@var{p}[@var{mod}] [@option{--plugin} @var{name}] [@option{--target} @var{bfdname}] [@option{--output} @var{dirname}] [@option{--record-libdeps} @var{libdeps}] [@var{relpos}] [@var{count}] @var{archive} [@var{member}@dots{}]
 ar -M [ <mri-script ]
 @end smallexample
 
@@ -196,7 +196,9 @@ characters (typical of formats related to coff).
 @cindex libraries
 @command{ar} is considered a binary utility because archives of this sort
 are most often used as @dfn{libraries} holding commonly needed
-subroutines.
+subroutines.  Since libraries often will depend on other libraries,
+@command{ar} can also record the dependencies of a library when the
+@option{--record-libdeps} option is specified.
 
 @cindex symbol index
 @command{ar} creates an index to the symbols defined in relocatable
@@ -254,7 +256,7 @@ program.
 
 @smallexample
 @c man begin SYNOPSIS ar
-ar [@option{-X32_64}] [@option{-}]@var{p}[@var{mod}] [@option{--plugin} @var{name}] [@option{--target} @var{bfdname}] [@option{--output} @var{dirname}] [@var{relpos}] [@var{count}] @var{archive} [@var{member}@dots{}]
+ar [@option{-X32_64}] [@option{-}]@var{p}[@var{mod}] [@option{--plugin} @var{name}] [@option{--target} @var{bfdname}] [@option{--output} @var{dirname}] [@option{--record-libdeps} @var{libdeps}] [@var{relpos}] [@var{count}] @var{archive} [@var{member}@dots{}]
 @c man end
 @end smallexample
 
@@ -448,9 +450,14 @@ member must be present as the @var{relpos} argument, before the
 @var{archive} specification.  (same as @samp{b}).
 
 @item l
-This modifier is accepted but not used.
+@c This modifier was accepted but not used.
 @c whaffor ar l modifier??? presumably compat; with
 @c what???---doc@@cygnus.com, 25jan91
+Specify dependencies of this library.  The dependencies must immediately
+follow this option character, must use the same syntax as the linker
+command line, and must be specified within a single argument.  I.e., if
+multiple items are needed, they must be quoted to form a single command
+line argument.  For example @samp{L "-L/usr/local/lib -lmydep1 -lmydep2"}
 
 @item N
 Uses the @var{count} parameter.  This is used if there are multiple
@@ -592,6 +599,10 @@ Note - although the presence of this option does imply a @option{x}
 extraction operation that option must still be included on the command
 line.
 
+@item --record-libdeps @var{libdeps}
+The @option{--record-libdeps} option is identical to the @option{l} modifier,
+just handled in long form.
+
 @end table
 @c man end
 
index c54e1083e5d5e91a6e74dcb5b6e4fdde45e502ef..726cb3b70c546d02cc7812bd06d856c115e113e1 100644 (file)
@@ -67,30 +67,20 @@ check_aix (bfd *try_bfd)
 }
 
 static bfd_boolean
-ar_emul_aix_append (bfd **after_bfd, char *file_name, const char *target,
+ar_emul_aix_append (bfd **after_bfd, bfd *new_bfd,
                    bfd_boolean verbose, bfd_boolean flatten)
 {
-  bfd *new_bfd;
-
-  new_bfd = bfd_openr (file_name, target);
-  AR_EMUL_ELEMENT_CHECK (new_bfd, file_name);
-
   return do_ar_emul_append (after_bfd, new_bfd, verbose, flatten, check_aix);
 }
 
 static bfd_boolean
-ar_emul_aix_replace (bfd **after_bfd, char *file_name, const char *target,
+ar_emul_aix_replace (bfd **after_bfd, bfd *new_bfd,
                     bfd_boolean verbose)
 {
-  bfd *new_bfd;
-
-  new_bfd = bfd_openr (file_name, target);
-  AR_EMUL_ELEMENT_CHECK (new_bfd, file_name);
-
   if (!check_aix (new_bfd))
     return FALSE;
 
-  AR_EMUL_REPLACE_PRINT_VERBOSE (verbose, file_name);
+  AR_EMUL_REPLACE_PRINT_VERBOSE (verbose, bfd_get_filename (new_bfd));
 
   new_bfd->archive_next = *after_bfd;
   *after_bfd = new_bfd;
index 5a9d27c6d0b04b25be4bf3685ac62dd94335fe2f..273a0a3909a2e4280365bd22d07cd25215f2d822 100644 (file)
@@ -715,6 +715,46 @@ proc many_files { } {
     pass $testname
 }
 
+proc test_add_dependencies { } {
+    global AR
+    global AS
+    global srcdir
+    global subdir
+    global obj
+
+    set testname "ar adding library dependencies"
+
+    if ![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.${obj}] {
+       unresolved $testname
+       return
+    }
+
+    if [is_remote host] {
+       set archive artest.a
+       set objfile [remote_download host tmpdir/bintest.${obj}]
+       remote_file host delete $archive
+    } else {
+       set archive tmpdir/artest.a
+       set objfile tmpdir/bintest.${obj}
+    }
+
+    remote_file build delete tmpdir/artest.a
+
+    set got [binutils_run $AR "-r -c $archive --record-libdeps /foo/bar ${objfile}"]
+    if ![string match "" $got] {
+       fail $testname
+       return
+    }
+
+    set got [binutils_run $AR "-t $archive"]
+    if ![string match "*bintest.${obj}\r__.LIBDEP*" $got] {
+       fail $testname
+       return
+    }
+
+    pass $testname
+}
+
 # Run the tests.
 
 # Only run the bfdtest checks if the programs exist.  Since these
@@ -743,6 +783,7 @@ move_an_element
 empty_archive
 extract_an_element
 many_files
+test_add_dependencies
 
 if { [is_elf_format] && [supports_gnu_unique] } {
     unique_symbol