Index: include/clang/Basic/DiagnosticDriverKinds.td =================================================================== --- include/clang/Basic/DiagnosticDriverKinds.td +++ include/clang/Basic/DiagnosticDriverKinds.td @@ -22,6 +22,8 @@ def err_drv_unknown_language : Error<"language not recognized: '%0'">; def err_drv_invalid_arch_name : Error< "invalid arch name '%0'">; +def err_drv_invalid_linker_name : Error< + "invalid linker name in argument '%0'">; def err_drv_invalid_rtlib_name : Error< "invalid runtime library name in argument '%0'">; def err_drv_unsupported_rtlib_for_platform : Error< Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -1542,7 +1542,7 @@ defm profile_use : BooleanFFlag<"profile-use">, Group; def fprofile_use_EQ : Joined<["-"], "fprofile-use=">, Group; -def fuse_ld_EQ : Joined<["-"], "fuse-ld=">, Group; +def fuse_ld_EQ : Joined<["-"], "fuse-ld=">, Group; defm align_functions : BooleanFFlag<"align-functions">, Group; def falign_functions_EQ : Joined<["-"], "falign-functions=">, Group; Index: include/clang/Driver/ToolChain.h =================================================================== --- include/clang/Driver/ToolChain.h +++ include/clang/Driver/ToolChain.h @@ -158,6 +158,10 @@ std::string GetFilePath(const char *Name) const; std::string GetProgramPath(const char *Name) const; + /// Returns the linker path, respecting the -fuse-ld= argument to determine + /// the linker suffix or name. + std::string GetLinkerPath() const; + /// \brief Dispatch to the specific toolchain for verbose printing. /// /// This is used when handling the verbose option to print detailed, Index: lib/Driver/ToolChain.cpp =================================================================== --- lib/Driver/ToolChain.cpp +++ lib/Driver/ToolChain.cpp @@ -15,6 +15,7 @@ #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "clang/Driver/ToolChain.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" @@ -147,6 +148,30 @@ return D.GetProgramPath(Name, *this); } +std::string ToolChain::GetLinkerPath() const { + if (Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { + StringRef Suffix = A->getValue(); + + // If we're passed -fuse-ld= with no argument, or with the argument ld, + // then use whatever the default system linker is. + if (Suffix.empty() || Suffix == "ld") + return GetProgramPath("ld"); + + llvm::SmallString<8> LinkerName("ld."); + LinkerName.append(Suffix); + + std::string LinkerPath(GetProgramPath(LinkerName.c_str())); + if (llvm::sys::fs::exists(LinkerPath)) + return LinkerPath; + + getDriver().Diag(diag::err_drv_invalid_linker_name) << A->getAsString(Args); + return ""; + } + + return GetProgramPath("ld"); +} + + types::ID ToolChain::LookupTypeForExtension(const char *Ext) const { return types::lookupTypeForExtension(Ext); } Index: lib/Driver/ToolChains.cpp =================================================================== --- lib/Driver/ToolChains.cpp +++ lib/Driver/ToolChains.cpp @@ -3001,7 +3001,7 @@ PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + GCCInstallation.getTriple().str() + "/bin").str()); - Linker = GetProgramPath("ld"); + Linker = GetLinkerPath(); Distro Distro = DetectDistro(Arch); Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -5612,7 +5612,7 @@ Args.AddAllArgs(CmdArgs, options::OPT_F); const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("ld")); + Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } @@ -5802,7 +5802,7 @@ addProfileRT(getToolChain(), Args, CmdArgs); const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("ld")); + Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } @@ -5910,7 +5910,7 @@ addProfileRT(getToolChain(), Args, CmdArgs); const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("ld")); + Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } @@ -6112,7 +6112,7 @@ } const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("ld")); + Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } @@ -6248,7 +6248,7 @@ } const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("ld")); + Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } @@ -6512,7 +6512,7 @@ addProfileRT(ToolChain, Args, CmdArgs); const char *Exec = - Args.MakeArgString(ToolChain.GetProgramPath("ld")); + Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } @@ -6765,7 +6765,7 @@ addProfileRT(getToolChain(), Args, CmdArgs); - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); + const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } @@ -7322,7 +7322,7 @@ Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); } - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); + const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } @@ -7500,7 +7500,7 @@ addProfileRT(getToolChain(), Args, CmdArgs); - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); + const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } Index: test/Driver/fuse-ld.c =================================================================== --- /dev/null +++ test/Driver/fuse-ld.c @@ -0,0 +1,63 @@ +// RUN: %clang %s -### \ +// RUN: -target x86_64-unknown-freebsd 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-FREEBSD-LD +// CHECK-FREEBSD-LD: ld + +// RUN: %clang %s -### -fuse-ld=bfd \ +// RUN: --sysroot=%S/Inputs/basic_freebsd_tree \ +// RUN: -target x86_64-unknown-freebsd \ +// RUN: -B%S/Inputs/basic_freebsd_tree/usr/bin 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-FREEBSD-BFD +// CHECK-FREEBSD-BFD: Inputs/basic_freebsd_tree/usr/bin/ld.bfd + +// RUN: %clang %s -### -fuse-ld=gold \ +// RUN: --sysroot=%S/Inputs/basic_freebsd_tree \ +// RUN: -target x86_64-unknown-freebsd \ +// RUN: -B%S/Inputs/basic_freebsd_tree/usr/bin 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-FREEBSD-GOLD +// CHECK-FREEBSD-GOLD: Inputs/basic_freebsd_tree/usr/bin/ld.gold + +// RUN: %clang %s -### -fuse-ld=plib \ +// RUN: --sysroot=%S/Inputs/basic_freebsd_tree \ +// RUN: -target x86_64-unknown-freebsd \ +// RUN: -B%S/Inputs/basic_freebsd_tree/usr/bin 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-FREEBSD-PLIB +// CHECK-FREEBSD-PLIB: error: invalid linker name + + + +// RUN: %clang %s -### \ +// RUN: -target arm-linux-androideabi \ +// RUN: -B%S/Inputs/basic_android_tree/bin 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-ANDROID-ARM-LD +// CHECK-ANDROID-ARM-LD: Inputs/basic_android_tree/bin/arm-linux-androideabi-ld + +// RUN: %clang %s -### -fuse-ld=bfd \ +// RUN: -target arm-linux-androideabi \ +// RUN: -B%S/Inputs/basic_android_tree/bin 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-ANDROID-ARM-BFD +// CHECK-ANDROID-ARM-BFD: Inputs/basic_android_tree/bin/arm-linux-androideabi-ld.bfd + +// RUN: %clang %s -### -fuse-ld=gold \ +// RUN: -target arm-linux-androideabi \ +// RUN: -B%S/Inputs/basic_android_tree/bin 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-ANDROID-ARM-GOLD +// CHECK-ANDROID-ARM-GOLD: Inputs/basic_android_tree/bin/arm-linux-androideabi-ld.gold + +// RUN: %clang %s -### \ +// RUN: -target arm-linux-androideabi \ +// RUN: -gcc-toolchain %S/Inputs/basic_android_tree 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-ANDROID-ARM-LD-TC +// CHECK-ANDROID-ARM-LD-TC: Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/bin/ld + +// RUN: %clang %s -### -fuse-ld=bfd \ +// RUN: -target arm-linux-androideabi \ +// RUN: -gcc-toolchain %S/Inputs/basic_android_tree 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-ANDROID-ARM-BFD-TC +// CHECK-ANDROID-ARM-BFD-TC: Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/bin/ld.bfd + +// RUN: %clang %s -### -fuse-ld=gold \ +// RUN: -target arm-linux-androideabi \ +// RUN: -gcc-toolchain %S/Inputs/basic_android_tree 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-ANDROID-ARM-GOLD-TC +// CHECK-ANDROID-ARM-GOLD-TC: Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/bin/ld.gold