https://github.com/bader created https://github.com/llvm/llvm-project/pull/201253
Add support for consuming static archives (.a, .lib) containing bitcode device libraries. When an archive is passed via --bc-library, each bitcode member is extracted and linked individually with LinkOnlyNeeded semantics, ensuring only referenced symbols are included in the output. Non-IR archive members (such as symbol tables or ELF objects) are silently skipped. Archives with mismatched target triples are filtered at the module level. This enables sanitizer runtimes and other device libraries to be packaged as static archives rather than individual bitcode files. >From 25ddbb1535a604a5520da76e7e93bb7b0701bb4b Mon Sep 17 00:00:00 2001 From: Alexey Bader <[email protected]> Date: Tue, 2 Jun 2026 19:57:29 -0700 Subject: [PATCH] [clang-sycl-linker] Add support for linking static archives Add support for consuming static archives (.a, .lib) containing bitcode device libraries. When an archive is passed via --bc-library, each bitcode member is extracted and linked individually with LinkOnlyNeeded semantics, ensuring only referenced symbols are included in the output. Non-IR archive members (such as symbol tables or ELF objects) are silently skipped. Archives with mismatched target triples are filtered at the module level. This enables sanitizer runtimes and other device libraries to be packaged as static archives rather than individual bitcode files. --- .../OffloadTools/clang-sycl-linker/link.ll | 11 +++++++ .../clang-sycl-linker/ClangSYCLLinker.cpp | 33 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/clang/test/OffloadTools/clang-sycl-linker/link.ll b/clang/test/OffloadTools/clang-sycl-linker/link.ll index 4114f0a3f3fb1..305f493e62dc5 100644 --- a/clang/test/OffloadTools/clang-sycl-linker/link.ll +++ b/clang/test/OffloadTools/clang-sycl-linker/link.ll @@ -34,6 +34,17 @@ ; Test that an absolute path to --bc-library is taken as-is, with no -L required. ; RUN: clang-sycl-linker %t/foo.bc %t/bar.bc --bc-library %t/libfoo.bc --dry-run -o a.spv --print-linked-module 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-DEVICE-LIB +; +; Test linking with a static archive of bitcode libraries. +; RUN: rm -f %t/libfoo.a +; RUN: llvm-ar rcs %t/libfoo.a %t/libfoo.bc +; RUN: clang-sycl-linker %t/foo.bc %t/bar.bc --bc-library %t/libfoo.a --dry-run -o a.spv --print-linked-module 2>&1 \ +; RUN: | FileCheck %s --check-prefix=CHECK-ARCHIVE +; CHECK-ARCHIVE: define {{.*}}foo_func1{{.*}} +; CHECK-ARCHIVE: define {{.*}}foo_func2{{.*}} +; CHECK-ARCHIVE: define {{.*}}bar_func1{{.*}} +; CHECK-ARCHIVE: define {{.*}}addFive{{.*}} +; CHECK-ARCHIVE-NOT: define {{.*}}unusedFunc{{.*}} ;--- foo.ll target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1" diff --git a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp index e5e092c4737ec..da2af2e4315dc 100644 --- a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp +++ b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp @@ -30,6 +30,7 @@ #include "llvm/LTO/LTO.h" #include "llvm/Linker/Linker.h" #include "llvm/MC/TargetRegistry.h" +#include "llvm/Object/Archive.h" #include "llvm/Object/Binary.h" #include "llvm/Object/IRObjectFile.h" #include "llvm/Object/OffloadBinary.h" @@ -341,6 +342,38 @@ static Expected<LinkResult> linkInputs(ArrayRef<std::string> InputFiles, // Link in library files. for (auto &File : *BCLibFiles) { + // Static archives are unpacked and each bitcode member is linked + // individually with LinkOnlyNeeded. + StringRef Ext = sys::path::extension(File); + if (Ext == ".a" || Ext == ".lib") { + auto BufOrErr = MemoryBuffer::getFile(File); + if (std::error_code EC = BufOrErr.getError()) + return createFileError(File, EC); + Expected<std::unique_ptr<object::Archive>> ArOrErr = + object::Archive::create((*BufOrErr)->getMemBufferRef()); + if (!ArOrErr) + return ArOrErr.takeError(); + Error ArErr = Error::success(); + for (const auto &Child : (*ArOrErr)->children(ArErr)) { + Expected<MemoryBufferRef> MemOrErr = Child.getMemoryBufferRef(); + if (!MemOrErr) + return MemOrErr.takeError(); + SMDiagnostic D; + std::unique_ptr<Module> Mod = getLazyIRModule( + MemoryBuffer::getMemBuffer(*MemOrErr, /*RequiresNullTerm=*/false), + D, C); + if (!Mod) { + // Skip non-IR archive members (e.g. symbol index, ELF objects). + continue; + } + if (Mod->getTargetTriple() == TargetTriple) + if (L.linkInModule(std::move(Mod), Linker::Flags::LinkOnlyNeeded)) + return createStringError("Could not link IR from " + File); + } + if (ArErr) + return std::move(ArErr); + continue; + } auto LibMod = getBitcodeModule(File, C); if (!LibMod) return LibMod.takeError(); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
