[RFC] Move static archive dependencies into ld

Michael Matz matz@suse.de
Fri Feb 17 15:03:57 GMT 2023


Hello,

this is an RFC for now.  When met with some acceptance I'll cobble up a 
similar thing for gold as well and then make the libdep.so plugin only 
emit a warning message that its functionality is obsoleted and moved 
into ld itself.  As Cary put it back in 2020 when the plugin was added:

( https://sourceware.org/pipermail/binutils/2020-December/114536.html )

"Did I miss any discussion about whether this feature should/could be
implemented directly in the linkers, rather than via a plugin? I
wouldn't be opposed to it."

I pretty much think that yes, the functionality absolutely needs to be in 
the linker itself, not in a plugin, at least if we want to see some use of 
it in the real world.  Amusingly I was triggered to look into this by 
libbfd itself:  Recently it got a dependency to libsframe and when 
shipping only static archives to build against (which we as distro 
consciously do) that leads to build errors in various 3rdparty packages 
wanting to link against libbfd (no matter how bad an idea that is).  Now, 
adding a '-plugin $magicdir/libdep.so' to the build flags of each such 
package is no better than just adding '-lsframe' in each case, so the 
plugin really doesn't help anything.  Had the functionality already been 
in the linker itself we could have just added 
"--record-libdeps='-lsframe'" when building libbfd.a and be done with it.

So, let's try to prepare for the future and at least now make ld interpret 
such dependencies on its own.

So, what do people think?


Ciao,
Michael.

---------------------------------------

needing a plugin to interpret static archive dependencies (as added
by 'ar --record-libdeps') effectively means they are unused.
Which is too bad, because they are actually useful.  So implement
them in ld itself.

 ld/ldmain.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 143 insertions(+), 1 deletion(-)

diff --git a/ld/ldmain.c b/ld/ldmain.c
index 8c2fc9b8d8c..dc86ddf3ca8 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -876,6 +876,143 @@ add_keepsyms_file (const char *filename)
   link_info.strip = strip_some;
   fclose (file);
 }
+
+/* Turn a string into an argvec.  */
+
+static char **
+str2vec (char *in)
+{
+  char **res;
+  char *s, *first, *end;
+  char *sq, *dq;
+  int i;
+
+  end = in + strlen (in);
+  s = in;
+  while (ISSPACE (*s)) s++;
+  first = s;
+
+  i = 1;
+  while ((s = strchr (s, ' ')))
+    {
+      s++;
+      i++;
+    }
+  res = (char **)xmalloc ((i+1) * sizeof (char *));
+  if (!res)
+    return res;
+
+  i = 0;
+  sq = NULL;
+  dq = NULL;
+  res[0] = first;
+  for (s = first; *s; s++)
+    {
+      if (*s == '\\')
+	{
+	  memmove (s, s+1, end-s-1);
+	  end--;
+	}
+      if (ISSPACE (*s))
+	{
+	  if (sq || dq)
+	    continue;
+	  *s++ = '\0';
+	  while (ISSPACE (*s)) s++;
+	  if (*s)
+	    res[++i] = s;
+	}
+      if (*s == '\'' && !dq)
+	{
+	  if (sq)
+	    {
+	      memmove (sq, sq+1, s-sq-1);
+	      memmove (s-2, s+1, end-s-1);
+	      end -= 2;
+	      s--;
+	      sq = NULL;
+	    }
+	  else
+	    {
+	      sq = s;
+	    }
+	}
+      if (*s == '"' && !sq)
+	{
+	  if (dq)
+	    {
+	      memmove (dq, dq+1, s-dq-1);
+	      memmove (s-2, s+1, end-s-1);
+	      end -= 2;
+	      s--;
+	      dq = NULL;
+	    }
+	  else
+	    {
+	      dq = s;
+	    }
+	}
+    }
+  res[++i] = NULL;
+  return res;
+}
+
+#define LIBDEPS "__.LIBDEP"
+
+/* Check if ARCHIVE has a '__.LIBDEP' member and if so interpret its
+   content as linker command line arguments (only -L and -l are accepted).
+   The special member is expected amongst the first few.  */
+
+static void
+check_archive_deps (bfd *archive)
+{
+  int count = 3;
+  bfd *member;
+
+  if (bfd_is_thin_archive (archive))
+    return;
+
+  /* We look for the magic member only in the first few archive
+     members.  */
+  member = bfd_openr_next_archived_file (archive, NULL);
+  while (member != NULL && count--)
+    {
+      ufile_ptr memsize = bfd_get_file_size (member);
+      if (memsize
+	  && !strcmp (bfd_get_filename (member), LIBDEPS))
+	{
+	  char *buf = (char *) xmalloc (memsize);
+	  if (buf
+	      && bfd_seek (member, (file_ptr) 0, SEEK_SET) == 0
+	      && bfd_bread (buf, memsize, member) == memsize)
+	    {
+	      char **vec;
+	      vec = str2vec (buf);
+	      if (vec)
+		{
+		  int i;
+		  for (i = 0; vec[i]; i++)
+		    {
+		      if (vec[i][0] != '-')
+			einfo ("ignoring libdep argument %s", vec[i]);
+		      else if (vec[i][1] == 'l')
+			lang_add_input_file (xstrdup (vec[i]+2),
+					     lang_input_file_is_l_enum,
+					     NULL);
+		      else if (vec[i][1] == 'L')
+			ldfile_add_library_path (vec[i]+2, false);
+		      else
+			einfo ("ignoring libdep argument %s", vec[i]);
+		    }
+		  free (vec);
+		}
+	    }
+	  free (buf);
+	  break;
+	}
+      member = bfd_openr_next_archived_file (archive, member);
+    }
+}
 
 /* Callbacks from the BFD linker routines.  */
 
@@ -941,7 +1078,12 @@ add_archive_element (struct bfd_link_info *info,
      from the archive.  See ldlang.c:find_rescan_insertion.  */
   parent = bfd_usrdata (abfd->my_archive);
   if (parent != NULL && !parent->flags.reload)
-    parent->next = input;
+    {
+      if (!parent->next)
+	/* The first time we see an archive use we check for dependencies.  */
+	check_archive_deps (abfd->my_archive);
+      parent->next = input;
+    }
 
   ldlang_add_file (input);
 
-- 
2.39.1


More information about the Binutils mailing list