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

Reply via email to