Skip to content

Commit b16f765

Browse files
authored
[LinkerWrapper] Accept some needed lld-link linker arguments for COFF targets (#72889)
Summary: The linker wrapper is a utility used to create offloading programs from single-source offloading languages such as OpenMP or CUDA. This is done by embedding device code into the host object, then feeding it into the linker wrapper which extracts the accelerator object files, links them, then wraps them in registration code for the target runtime. This previously has only worked in Linux / ELF platforms. This patch attempts to hand Windows / COFF inputs by also accepting COFF forms of certain linker arguments we use internally. The important arguments are library search paths, so we can identify libraries which may contain device code, libraries themselves, and the output name used for intermediate output. I am not intimately familiar with the semantics here for the semantics in how a `lib` file is earched. I am simply treating `foo.lib` as the GNU equivalent `-l:foo.lib` in the search logic. Similarly, I am assuming that static libraries will be llvm-ar style libraries. I will need to investigate the actual deficiencies later, but this should be a good starting point along with #72697
1 parent 6b3470b commit b16f765

File tree

3 files changed

+26
-5
lines changed

3 files changed

+26
-5
lines changed

clang/test/Driver/linker-wrapper.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,11 @@
140140
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=CLANG-BACKEND
141141

142142
// CLANG-BACKEND: clang{{.*}} -o {{.*}}.img --target=amdgcn-amd-amdhsa -mcpu=gfx908 -O2 -Wl,--no-undefined {{.*}}.bc
143+
144+
// RUN: clang-offload-packager -o %t.out \
145+
// RUN: --image=file=%t.elf.o,kind=openmp,triple=nvptx64-nvidia-cuda,arch=sm_70
146+
// RUN: %clang -cc1 %s -triple x86_64-unknown-windows-msvc -emit-obj -o %t.o -fembed-offload-object=%t.out
147+
// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-windows-msvc --dry-run \
148+
// RUN: --linker-path=/usr/bin/lld-link -- %t.o -libpath:./ -out:a.exe 2>&1 | FileCheck %s --check-prefix=COFF
149+
150+
// COFF: "/usr/bin/lld-link" {{.*}}.o -libpath:./ -out:a.exe {{.*}}openmp.image.wrapper{{.*}}

clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ Error runLinker(ArrayRef<StringRef> Files, const ArgList &Args) {
254254
continue;
255255

256256
Arg->render(Args, NewLinkerArgs);
257-
if (Arg->getOption().matches(OPT_o))
257+
if (Arg->getOption().matches(OPT_o) || Arg->getOption().matches(OPT_out))
258258
llvm::transform(Files, std::back_inserter(NewLinkerArgs),
259259
[&](StringRef Arg) { return Args.MakeArgString(Arg); });
260260
}
@@ -1188,7 +1188,7 @@ searchLibraryBaseName(StringRef Name, StringRef Root,
11881188
/// `-lfoo` or `-l:libfoo.a`.
11891189
std::optional<std::string> searchLibrary(StringRef Input, StringRef Root,
11901190
ArrayRef<StringRef> SearchPaths) {
1191-
if (Input.startswith(":"))
1191+
if (Input.startswith(":") || Input.ends_with(".lib"))
11921192
return findFromSearchPaths(Input.drop_front(), Root, SearchPaths);
11931193
return searchLibraryBaseName(Input, Root, SearchPaths);
11941194
}
@@ -1339,7 +1339,7 @@ Expected<SmallVector<OffloadFile>> getDeviceInput(const ArgList &Args) {
13391339

13401340
StringRef Root = Args.getLastArgValue(OPT_sysroot_EQ);
13411341
SmallVector<StringRef> LibraryPaths;
1342-
for (const opt::Arg *Arg : Args.filtered(OPT_library_path))
1342+
for (const opt::Arg *Arg : Args.filtered(OPT_library_path, OPT_libpath))
13431343
LibraryPaths.push_back(Arg->getValue());
13441344

13451345
BumpPtrAllocator Alloc;
@@ -1348,7 +1348,7 @@ Expected<SmallVector<OffloadFile>> getDeviceInput(const ArgList &Args) {
13481348
// Try to extract device code from the linker input files.
13491349
SmallVector<OffloadFile> InputFiles;
13501350
DenseMap<OffloadFile::TargetID, DenseMap<StringRef, Symbol>> Syms;
1351-
bool WholeArchive = false;
1351+
bool WholeArchive = Args.hasArg(OPT_wholearchive_flag) ? true : false;
13521352
for (const opt::Arg *Arg : Args.filtered(
13531353
OPT_INPUT, OPT_library, OPT_whole_archive, OPT_no_whole_archive)) {
13541354
if (Arg->getOption().matches(OPT_whole_archive) ||
@@ -1474,9 +1474,17 @@ int main(int Argc, char **Argv) {
14741474
Verbose = Args.hasArg(OPT_verbose);
14751475
DryRun = Args.hasArg(OPT_dry_run);
14761476
SaveTemps = Args.hasArg(OPT_save_temps);
1477-
ExecutableName = Args.getLastArgValue(OPT_o, "a.out");
14781477
CudaBinaryPath = Args.getLastArgValue(OPT_cuda_path_EQ).str();
14791478

1479+
llvm::Triple Triple(
1480+
Args.getLastArgValue(OPT_host_triple_EQ, sys::getDefaultTargetTriple()));
1481+
if (Args.hasArg(OPT_o))
1482+
ExecutableName = Args.getLastArgValue(OPT_o, "a.out");
1483+
else if (Args.hasArg(OPT_out))
1484+
ExecutableName = Args.getLastArgValue(OPT_out, "a.exe");
1485+
else
1486+
ExecutableName = Triple.isOSWindows() ? "a.exe" : "a.out";
1487+
14801488
parallel::strategy = hardware_concurrency(1);
14811489
if (auto *Arg = Args.getLastArg(OPT_wrapper_jobs)) {
14821490
unsigned Threads = 0;

clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,8 @@ def version : Flag<["--", "-"], "version">, Flags<[HelpHidden]>, Alias<v>;
126126

127127
def whole_archive : Flag<["--", "-"], "whole-archive">, Flags<[HelpHidden]>;
128128
def no_whole_archive : Flag<["--", "-"], "no-whole-archive">, Flags<[HelpHidden]>;
129+
130+
// link.exe-style linker options.
131+
def out : Joined<["/", "-", "/?", "-?"], "out:">, Flags<[HelpHidden]>;
132+
def libpath : Joined<["/", "-", "/?", "-?"], "libpath:">, Flags<[HelpHidden]>;
133+
def wholearchive_flag : Joined<["/", "-", "/?", "-?"], "wholearchive">, Flags<[HelpHidden]>;

0 commit comments

Comments
 (0)