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
