To give a sense of the kind of change required to get the feature I
want, see the patch at the end. The change in DriverUtils.cpp is just to
show that the same function is hiding in there.

If this looks like a good direction, I can cleanup the code and maybe it
could be shared, though I'm not sure where this would belong. Maybe a
new tiny library of such wrappers to maintain in our tree?

Thanks
Greg

P.S. Naturally, once I install this patched cc, ghci is suddenly very
happy.

Greg Steuck <[email protected]> writes:

> Since OpenBSD always uses .so.major.minor I observe GHCi running into
> trouble when resolving -l on its own. The way it tries to find the
> shared object to load is by relying on `cc --print-file-name`. I see
> this:
> $ ghci -v -lc++
> ...
> Search directories (gcc):
> *** systool:linker:
> *** gcc:
> cc -Wl,-z,wxneeded --print-file-name 'libc++.so'
> !!! systool:linker: finished in 0.00 milliseconds, allocated 0.059 megabytes
> *** systool:linker:
> *** gcc:
> cc -Wl,-z,wxneeded --print-file-name 'liblibc++.so'
> !!! systool:linker: finished in 0.00 milliseconds, allocated 0.054 megabytes
> *** systool:linker:
> *** gcc:
> cc -Wl,-z,wxneeded --print-file-name 'c++.lib'
>
> Which never succeeds, because the only way this could work is if ghc
> knew the version number:
> % cc --print-file-name 'libc++.so.9.0'
> /usr/lib/libc++.so.9.0
>
> It feels like I need to somehow convince cc --print-file-name to get in here:
> ports/devel/llvm/patches/patch-tools_lld_ELF_DriverUtils_cpp
>
> Would it be a good idea to extend clang's --print-file-name in such a
> way that both versioned and unversioned variations work? I.e. make the
> second command works the same as the first one below?
>
> % cc --print-file-name libc++.so.9.0
> /usr/lib/libc++.so.9.0
> % cc --print-file-name libc++.so
> libc++.so
>
> Thanks
> Greg

>From 825207a1ec5b0f0941bf5a624a862c9f460ddf94 Mon Sep 17 00:00:00 2001
From: Greg Steuck <[email protected]>
Date: Sun, 13 Feb 2022 22:28:43 -0800
Subject: [PATCH] Find --print-file-name versioned lib.so's for the given short
 name

This is a complement of the major.minor finding logic in DriverUtils.
To make things more obviously related the same code was extracted into
a function which was copied modulo namespaces and minor parameter
adjustments
---
 gnu/llvm/clang/lib/Driver/Driver.cpp | 54 ++++++++++++++++++++++++--
 gnu/llvm/lld/ELF/DriverUtils.cpp     | 57 +++++++++++++++-------------
 2 files changed, 82 insertions(+), 29 deletions(-)

diff --git a/gnu/llvm/clang/lib/Driver/Driver.cpp 
b/gnu/llvm/clang/lib/Driver/Driver.cpp
index 94a7553e273..cdf95ac6c9f 100644
--- a/gnu/llvm/clang/lib/Driver/Driver.cpp
+++ b/gnu/llvm/clang/lib/Driver/Driver.cpp
@@ -5089,7 +5089,50 @@ const char *Driver::GetNamedOutputPath(Compilation &C, 
const JobAction &JA,
   }
 }
 
+
+namespace {
+static Optional<std::string> findFile(StringRef path1, const Twine &path2) {
+  SmallString<128> s;
+  llvm::sys::path::append(s, path1, path2);
+
+  if (llvm::sys::fs::exists(s))
+    return std::string(s);
+  return None;
+}
+
+llvm::Optional<std::string> findMajMinShlib(StringRef dir, StringRef 
libNameSo) {
+  // Handle OpenBSD-style maj/min shlib scheme
+  llvm::SmallString<128> Scratch;
+  const StringRef LibName = (libNameSo + ".").toStringRef(Scratch);
+  int MaxMaj = -1, MaxMin = -1;
+  std::error_code EC;
+  for (llvm::sys::fs::directory_iterator LI(dir, EC), LE;
+       LI != LE; LI = LI.increment(EC)) {
+    StringRef FilePath = LI->path();
+    StringRef FileName = llvm::sys::path::filename(FilePath);
+    if (!(FileName.startswith(LibName)))
+      continue;
+    std::pair<StringRef, StringRef> MajMin =
+      FileName.substr(LibName.size()).split('.');
+    int Maj, Min;
+    if (MajMin.first.getAsInteger(10, Maj) || Maj < 0)
+      continue;
+    if (MajMin.second.getAsInteger(10, Min) || Min < 0)
+      continue;
+    if (Maj > MaxMaj)
+      MaxMaj = Maj, MaxMin = Min;
+    if (MaxMaj == Maj && Min > MaxMin)
+      MaxMin = Min;
+  }
+  if (MaxMaj >= 0)
+    return findFile(dir, LibName + Twine(MaxMaj) + "." + Twine(MaxMin));
+  return None;
+}
+
+}
+
 std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const {
+  const bool lookForLibDotSo = Name.startswith("lib") && Name.endswith(".so");
   // Search for Name in a list of paths.
   auto SearchPaths = [&](const llvm::SmallVectorImpl<std::string> &P)
       -> llvm::Optional<std::string> {
@@ -5099,9 +5142,14 @@ std::string Driver::GetFilePath(StringRef Name, const 
ToolChain &TC) const {
       if (Dir.empty())
         continue;
       SmallString<128> P(Dir[0] == '=' ? SysRoot + Dir.substr(1) : Dir);
-      llvm::sys::path::append(P, Name);
-      if (llvm::sys::fs::exists(Twine(P)))
-        return std::string(P);
+      if (!lookForLibDotSo) {
+       llvm::sys::path::append(P, Name);
+       if (llvm::sys::fs::exists(Twine(P)))
+         return std::string(P);
+      } else {
+       if (auto s = findMajMinShlib(P, Name))
+         return std::string(*s);
+      }
     }
     return None;
   };
diff --git a/gnu/llvm/lld/ELF/DriverUtils.cpp b/gnu/llvm/lld/ELF/DriverUtils.cpp
index 6b164e30677..2b88ed3d3b3 100644
--- a/gnu/llvm/lld/ELF/DriverUtils.cpp
+++ b/gnu/llvm/lld/ELF/DriverUtils.cpp
@@ -230,6 +230,35 @@ Optional<std::string> elf::findFromSearchPaths(StringRef 
path) {
   return None;
 }
 
+Optional<std::string> findMajMinShlib(StringRef dir, StringRef name) {
+  // Handle OpenBSD-style maj/min shlib scheme
+  llvm::SmallString<128> Scratch;
+  const StringRef LibName = ("lib" + name + ".so.").toStringRef(Scratch);
+  int MaxMaj = -1, MaxMin = -1;
+  std::error_code EC;
+  for (fs::directory_iterator LI(dir, EC), LE;
+       LI != LE; LI = LI.increment(EC)) {
+    StringRef FilePath = LI->path();
+    StringRef FileName = path::filename(FilePath);
+    if (!(FileName.startswith(LibName)))
+      continue;
+    std::pair<StringRef, StringRef> MajMin =
+      FileName.substr(LibName.size()).split('.');
+    int Maj, Min;
+    if (MajMin.first.getAsInteger(10, Maj) || Maj < 0)
+      continue;
+    if (MajMin.second.getAsInteger(10, Min) || Min < 0)
+      continue;
+    if (Maj > MaxMaj)
+      MaxMaj = Maj, MaxMin = Min;
+    if (MaxMaj == Maj && Min > MaxMin)
+      MaxMin = Min;
+  }
+  if (MaxMaj >= 0)
+    return findFile(dir, LibName + Twine(MaxMaj) + "." + Twine(MaxMin));
+  return None;
+}
+
 // This is for -l<basename>. We'll look for lib<basename>.so or 
lib<basename>.a from
 // search paths.
 Optional<std::string> elf::searchLibraryBaseName(StringRef name) {
@@ -237,32 +266,8 @@ Optional<std::string> elf::searchLibraryBaseName(StringRef 
name) {
     if (!config->isStatic) {
       if (Optional<std::string> s = findFile(dir, "lib" + name + ".so"))
         return s;
-
-      // Handle OpenBSD-style maj/min shlib scheme
-      llvm::SmallString<128> Scratch;
-      const StringRef LibName = ("lib" + name + ".so.").toStringRef(Scratch);
-      int MaxMaj = -1, MaxMin = -1;
-      std::error_code EC;
-      for (fs::directory_iterator LI(dir, EC), LE;
-          LI != LE; LI = LI.increment(EC)) {
-        StringRef FilePath = LI->path();
-        StringRef FileName = path::filename(FilePath);
-        if (!(FileName.startswith(LibName)))
-          continue;
-        std::pair<StringRef, StringRef> MajMin =
-          FileName.substr(LibName.size()).split('.');
-        int Maj, Min;
-        if (MajMin.first.getAsInteger(10, Maj) || Maj < 0)
-          continue;
-        if (MajMin.second.getAsInteger(10, Min) || Min < 0)
-          continue;
-        if (Maj > MaxMaj)
-          MaxMaj = Maj, MaxMin = Min;
-        if (MaxMaj == Maj && Min > MaxMin)
-          MaxMin = Min;
-      }
-      if (MaxMaj >= 0)
-        return findFile(dir, LibName + Twine(MaxMaj) + "." + Twine(MaxMin));
+      if (Optional<std::string> s = findMajMinShlib(dir, name))
+        return s;
     }
     if (Optional<std::string> s = findFile(dir, "lib" + name + ".a"))
       return s;
-- 
2.35.1

Reply via email to