public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [RFC] Move static archive dependencies into ld
@ 2023-02-17 15:03 Michael Matz
  2023-02-17 20:53 ` Howard Chu
  0 siblings, 1 reply; 5+ messages in thread
From: Michael Matz @ 2023-02-17 15:03 UTC (permalink / raw)
  To: binutils

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);
+    }
+}
 \f
 /* 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

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2023-06-05 15:32 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-17 15:03 [RFC] Move static archive dependencies into ld Michael Matz
2023-02-17 20:53 ` Howard Chu
2023-04-13  9:10   ` Clément Chigot
2023-06-05 14:16   ` Howard Chu
2023-06-05 15:32     ` Michael Matz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).