[clang] [llvm] [clang][sycl][nvlink] Share static library linking in Frontend/Offloading (PR #201253)
Alexey Bader via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 5 11:50:13 PDT 2026
================
@@ -0,0 +1,276 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements shared functionality for linking static libraries
+// (archives) in offloading tools.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Frontend/Offloading/ArchiveLinker.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/IRObjectFile.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include <optional>
+#include <string>
+
+using namespace llvm;
+using namespace llvm::object;
+
+namespace llvm {
+namespace offloading {
+
+Expected<Symbol> Symbol::createFromObject(MemoryBufferRef File,
+ const SymbolRef &Sym) {
+ Symbol Result;
+ Result.File = File;
+
+ auto FlagsOrErr = Sym.getFlags();
+ if (!FlagsOrErr)
+ return FlagsOrErr.takeError();
+
+ if (*FlagsOrErr & SymbolRef::SF_Undefined)
+ Result.SymFlags |= Undefined;
+ if (*FlagsOrErr & SymbolRef::SF_Weak)
+ Result.SymFlags |= Weak;
+
+ return Result;
+}
+
+static std::optional<std::string> findFile(StringRef Dir, StringRef Root,
+ const Twine &Name) {
+ SmallString<128> Path;
+ if (Dir.starts_with("="))
+ sys::path::append(Path, Root, Dir.substr(1), Name);
+ else
+ sys::path::append(Path, Dir, Name);
+
+ if (sys::fs::exists(Path))
+ return static_cast<std::string>(Path);
+ return std::nullopt;
+}
+
+static std::optional<std::string>
+findFromSearchPaths(StringRef Name, StringRef Root,
+ ArrayRef<StringRef> SearchPaths) {
+ for (StringRef Dir : SearchPaths)
+ if (std::optional<std::string> File = findFile(Dir, Root, Name))
+ return File;
+ return std::nullopt;
+}
+
+/// Search for static libraries in the linker's library path given input like
+/// `-lfoo` or `-l:libfoo.a`.
+static std::optional<std::string>
+searchLibrary(StringRef Input, StringRef Root,
+ ArrayRef<StringRef> SearchPaths) {
+ if (Input.starts_with(":"))
+ return findFromSearchPaths(Input.drop_front(), Root, SearchPaths);
+ SmallString<128> LibName;
+ ("lib" + Input + ".a").toVector(LibName);
+ return findFromSearchPaths(LibName, Root, SearchPaths);
+}
+
+static Expected<bool> getSymbolsFromBitcode(MemoryBufferRef Buffer,
+ StringMap<Symbol> &SymTab,
+ bool IsLazy) {
+ Expected<IRSymtabFile> IRSymtabOrErr = readIRSymtab(Buffer);
+ if (!IRSymtabOrErr)
+ return IRSymtabOrErr.takeError();
+ bool Extracted = !IsLazy;
+ StringMap<Symbol> PendingSymbols;
+ for (unsigned I = 0; I != IRSymtabOrErr->Mods.size(); ++I) {
+ for (const auto &IRSym : IRSymtabOrErr->TheReader.module_symbols(I)) {
+ if (IRSym.isFormatSpecific() || !IRSym.isGlobal())
+ continue;
+
+ StringMap<Symbol> &Target =
+ (IsLazy && !SymTab.count(IRSym.getName())) ? PendingSymbols : SymTab;
+ Symbol &OldSym = Target[IRSym.getName()];
+ Symbol Sym = Symbol(Buffer, IRSym);
+ if (OldSym.File.getBuffer().empty())
+ OldSym = Sym;
+
+ bool ResolvesReference =
+ !Sym.isUndefined() &&
+ (OldSym.isUndefined() || (OldSym.isWeak() && !Sym.isWeak())) &&
+ !(OldSym.isWeak() && OldSym.isUndefined() && IsLazy);
+ Extracted |= ResolvesReference;
+
+ Sym.UsedInRegularObj = OldSym.UsedInRegularObj;
+ if (ResolvesReference)
+ OldSym = Sym;
+ }
+ }
+ if (Extracted)
+ for (const auto &[Name, Symbol] : PendingSymbols)
+ SymTab[Name] = Symbol;
+ return Extracted;
+}
+
+static Expected<bool> getSymbolsFromObject(ObjectFile &ObjFile,
+ StringMap<Symbol> &SymTab,
+ bool IsLazy) {
+ bool Extracted = !IsLazy;
+ StringMap<Symbol> PendingSymbols;
+ for (SymbolRef ObjSym : ObjFile.symbols()) {
+ auto NameOrErr = ObjSym.getName();
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+
+ StringMap<Symbol> &Target =
+ (IsLazy && !SymTab.count(*NameOrErr)) ? PendingSymbols : SymTab;
+ Symbol &OldSym = Target[*NameOrErr];
+
+ auto SymOrErr =
+ Symbol::createFromObject(ObjFile.getMemoryBufferRef(), ObjSym);
+ if (!SymOrErr)
+ return SymOrErr.takeError();
+ Symbol Sym = *SymOrErr;
+
+ if (OldSym.File.getBuffer().empty())
+ OldSym = Sym;
+
+ bool ResolvesReference = OldSym.isUndefined() && !Sym.isUndefined() &&
+ (!OldSym.isWeak() || !IsLazy);
+ Extracted |= ResolvesReference;
+
+ if (ResolvesReference)
+ OldSym = Sym;
+ OldSym.UsedInRegularObj = true;
+ }
+ if (Extracted)
+ for (const auto &[Name, Symbol] : PendingSymbols)
+ SymTab[Name] = Symbol;
+ return Extracted;
+}
+
+static Expected<bool> getSymbols(MemoryBufferRef Buffer,
+ StringMap<Symbol> &SymTab, bool IsLazy) {
+ switch (identify_magic(Buffer.getBuffer())) {
+ case file_magic::bitcode: {
+ return getSymbolsFromBitcode(Buffer, SymTab, IsLazy);
+ }
+ case file_magic::elf_relocatable: {
+ Expected<std::unique_ptr<ObjectFile>> ObjFile =
+ ObjectFile::createObjectFile(Buffer);
+ if (!ObjFile)
+ return ObjFile.takeError();
+ return getSymbolsFromObject(**ObjFile, SymTab, IsLazy);
+ }
+ default:
+ return createStringError("Unsupported file type: '" +
+ Buffer.getBufferIdentifier() + "'");
+ }
+}
+
+Expected<ResolvedInputs>
+resolveArchiveMembers(const Inputs &In,
+ function_ref<bool(MemoryBufferRef)> IsFatBinary) {
----------------
bader wrote:
Please, check if 2ac9bed8e2d7 matches your thinking.
https://github.com/llvm/llvm-project/pull/201253
More information about the cfe-commits
mailing list