[cfe-dev] Adding -fuse-ld= support to clang

David Chisnall David.Chisnall at cl.cam.ac.uk
Sat May 18 08:00:36 PDT 2013


Hi Everyone,

In FreeBSD, we are about to start the process of migrating from (ancient) BFD ld to MCLinker, so we're going to need support for multiple linkers for a while.  It turns out that gcc already has an option to select linkers, so I have attempted to remain compatible in the attached patch.  This adds a -fuse-ld={name} option, which takes a string as an argument.  The toolchains then request a linker and get either ld.{name}, ld-{name}, or {name} as the linker.  

Does anyone have objections to committing this as-is, or would anyone like to recommend a better approach?

David

Index: include/clang/Basic/DiagnosticDriverKinds.td
===================================================================
--- include/clang/Basic/DiagnosticDriverKinds.td	(revision 182184)
+++ include/clang/Basic/DiagnosticDriverKinds.td	(working copy)
@@ -26,6 +26,8 @@
   "unsupported runtime library '%0' for platform '%1'">;
 def err_drv_invalid_stdlib_name : Error<
   "invalid library name in argument '%0'">;
+def err_drv_invalid_linker_name : Error<
+  "invalid linker name in argument '%0'">;
 def err_drv_invalid_opt_with_multiple_archs : Error<
   "option '%0' cannot be used with multiple -arch options">;
 def err_drv_invalid_output_with_multiple_archs : Error<
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td	(revision 182184)
+++ include/clang/Driver/Options.td	(working copy)
@@ -744,6 +744,8 @@
 def fuse_cxa_atexit : Flag<["-"], "fuse-cxa-atexit">, Group<f_Group>;
 def fuse_init_array : Flag<["-"], "fuse-init-array">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Use .init_array instead of .ctors">;
+def fuse_ld_EQ : Joined<["-", "--"], "fuse-ld=">, Group<f_Group>,
+  HelpText<"The linker to use.">;
 def fverbose_asm : Flag<["-"], "fverbose-asm">, Group<f_Group>;
 def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group<f_Group>,
   HelpText<"Set the default symbol visibility for all global declarations">;
Index: include/clang/Driver/ToolChain.h
===================================================================
--- include/clang/Driver/ToolChain.h	(revision 182184)
+++ include/clang/Driver/ToolChain.h	(working copy)
@@ -136,6 +136,9 @@
 
   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;
 
   // Platform defaults information
 
Index: lib/Driver/ToolChain.cpp
===================================================================
--- lib/Driver/ToolChain.cpp	(revision 182184)
+++ lib/Driver/ToolChain.cpp	(working copy)
@@ -132,6 +132,36 @@
 
 }
 
+std::string ToolChain::GetLinkerPath() const {
+  if (Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) {
+    StringRef Value = 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 (Value.empty() || Value == "ld")
+      return GetFilePath("ld");
+    std::string LinkerName = Value.str();
+    std::string LD("ld.");
+    LD += LinkerName;
+    std::string LinkerPath = GetFilePath(LD.c_str());
+    bool Exists;
+    if (!llvm::sys::fs::exists(LinkerPath, Exists) && Exists)
+      return LinkerPath;
+    LD = std::string("ld-") + LinkerName;
+    LinkerPath = GetFilePath(LD.c_str());
+    if (!llvm::sys::fs::exists(LinkerPath, Exists) && Exists)
+      return LinkerPath;
+    LinkerPath = GetFilePath(LinkerName.c_str());
+    if (!llvm::sys::fs::exists(LinkerPath, Exists) && Exists)
+      return LinkerPath;
+    getDriver().Diag(diag::err_drv_invalid_linker_name)
+      << A->getAsString(Args);
+    // Fall through and run the system linker - we could do a hard error here,
+    // but we may as well try and see if it works.
+  }
+  return GetFilePath("ld");
+}
+
+
 std::string ToolChain::GetProgramPath(const char *Name) const {
   return D.GetProgramPath(Name, *this);
 }
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp	(revision 182184)
+++ lib/Driver/Tools.cpp	(working copy)
@@ -5219,8 +5219,7 @@
                               getToolChain().GetFilePath("crtendS.o")));
   }
 
-  const char *Exec =
-    Args.MakeArgString(getToolChain().GetProgramPath("ld"));
+  const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
   C.addCommand(new Command(JA, *this, Exec, CmdArgs));
 }
 
@@ -5361,8 +5360,7 @@
                               getToolChain().GetFilePath("crtendS.o")));
   }
 
-  const char *Exec =
-    Args.MakeArgString(getToolChain().GetProgramPath("ld"));
+  const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
   C.addCommand(new Command(JA, *this, Exec, CmdArgs));
 }
 
@@ -5612,8 +5610,7 @@
 
   addProfileRT(ToolChain, Args, CmdArgs, ToolChain.getTriple());
 
-  const char *Exec =
-    Args.MakeArgString(ToolChain.GetProgramPath("ld"));
+  const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
   C.addCommand(new Command(JA, *this, Exec, CmdArgs));
 }
 
@@ -5762,7 +5759,7 @@
 
   addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
 
-  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld"));
+  const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
   C.addCommand(new Command(JA, *this, Exec, CmdArgs));
 }
 
@@ -6247,7 +6244,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));
 }
 
@@ -6430,8 +6427,7 @@
 
   addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
 
-  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
===================================================================
--- test/Driver/fuse_ld.c	(revision 0)
+++ test/Driver/fuse_ld.c	(working copy)
@@ -0,0 +1,7 @@
+// RUN: rm -f ld.foo
+// RUN: %clang %s -target i386-unknown-freebsd -fuse-ld=foo -### 2>&1 | FileCheck -check-prefix=MISSING %s
+// RUN: touch ld.foo
+// RUN: %clang %s -B. -target i386-unknown-freebsd -fuse-ld=foo -### 2>&1 | FileCheck -check-prefix=FOUND %s
+
+// CHECK-MISSING: error: invalid linker name in argument '-fuse-ld=foo'
+// CHECK-FOUND: "./ld.foo"





More information about the cfe-dev mailing list