]> granicus.if.org Git - clang/commitdiff
Driver: add a cygwin linker tool
authorSaleem Abdulrasool <compnerd@compnerd.org>
Sun, 29 Jun 2014 06:11:14 +0000 (06:11 +0000)
committerSaleem Abdulrasool <compnerd@compnerd.org>
Sun, 29 Jun 2014 06:11:14 +0000 (06:11 +0000)
This adds a linker tool for the Windows cygwin environment.  This linker
invocation is significantly different from the generic ld invocation.  It
requires additional parameters as well as does not accept some normal
parameters.  This should fix self-hosting on Cygwin.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@211995 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Driver/Options.td
lib/Driver/Driver.cpp
lib/Driver/ToolChains.cpp
lib/Driver/ToolChains.h
lib/Driver/Tools.cpp
lib/Driver/Tools.h
test/Driver/cygwin-link.c [new file with mode: 0644]

index 95f13cc384532c0bece9123396c4fc76b392c7aa..f43c4df06f84763d838085aed8aa3fc2dac53183 100644 (file)
@@ -1019,6 +1019,7 @@ def masm_EQ : Joined<["-"], "masm=">, Group<m_Group>, Flags<[DriverOption]>;
 def mcmodel_EQ : Joined<["-"], "mcmodel=">, Group<m_Group>;
 def mconstant_cfstrings : Flag<["-"], "mconstant-cfstrings">, Group<clang_ignored_m_Group>;
 def mcpu_EQ : Joined<["-"], "mcpu=">, Group<m_Group>;
+def mdll : Joined<["-"], "mdll">, Group<m_Group>, Flags<[DriverOption]>;
 def mdynamic_no_pic : Joined<["-"], "mdynamic-no-pic">, Group<m_Group>;
 def mfix_and_continue : Flag<["-"], "mfix-and-continue">, Group<clang_ignored_m_Group>;
 def mieee_fp : Flag<["-"], "mieee-fp">, Group<clang_ignored_m_Group>;
index a18312a84fa08ca4c1c18e3bf87d2362640b64b6..7ef19ce60fa5e53a36ec832ca258df347072d4b9 100644 (file)
@@ -2023,6 +2023,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
         else
           TC = new toolchains::Generic_GCC(*this, Target, Args);
         break;
+      case llvm::Triple::Cygnus:
+        TC = new toolchains::Cygwin(*this, Target, Args);
+        break;
       case llvm::Triple::MSVC:
       case llvm::Triple::UnknownEnvironment:
         TC = new toolchains::Windows(*this, Target, Args);
index c01f0326a04733f0f1f8535ecc176ad94d071519..4efc9a1078263a082dcdd6692752eead40e07a88 100644 (file)
@@ -3476,6 +3476,17 @@ Tool *DragonFly::buildLinker() const {
   return new tools::dragonfly::Link(*this);
 }
 
+/// Cygwin toolchain
+Cygwin::Cygwin(const Driver &D, const llvm::Triple &Triple,
+               const llvm::opt::ArgList &Args)
+    : Generic_GCC(D, Triple, Args) {
+  ToolChain::path_list &LibPaths = getFilePaths();
+  LibPaths.push_back("/usr/lib");
+}
+
+Tool *Cygwin::buildLinker() const {
+  return new tools::cygwin::Link(*this);
+}
 
 /// XCore tool chain
 XCore::XCore(const Driver &D, const llvm::Triple &Triple,
index 8931aec7899a7170b575ff7314235d0d17e06ed5..66d7eef53ad5b5d8b1718c8404efdae652e93598 100644 (file)
@@ -744,6 +744,14 @@ protected:
   Tool *buildAssembler() const override;
 };
 
+class LLVM_LIBRARY_VISIBILITY Cygwin : public Generic_GCC {
+public:
+  Cygwin(const Driver &D, const llvm::Triple &Triple,
+         const llvm::opt::ArgList &Args);
+
+protected:
+  Tool *buildLinker() const override;
+};
 
 class LLVM_LIBRARY_VISIBILITY XCore : public ToolChain {
 public:
index 06c681091d0c11b02bad307fc847b54b785b0553..24d4bf90a9b470ab6c8a505377ed405753f4ae85 100644 (file)
@@ -7315,6 +7315,172 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
   C.addCommand(new Command(JA, *this, Exec, CmdArgs));
 }
 
+void cygwin::Link::AddLibGCC(const ArgList &Args, ArgStringList &CmdArgs) const {
+  if (Args.hasArg(options::OPT_static) ||
+      Args.hasArg(options::OPT_static_libgcc)) {
+    CmdArgs.push_back("-lgcc");
+    CmdArgs.push_back("-lgcc_eh");
+  } else {
+    CmdArgs.push_back("-lgcc_s");
+    CmdArgs.push_back("-lgcc");
+  }
+}
+
+void cygwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
+                                const InputInfo &Output,
+                                const InputInfoList &Inputs,
+                                const llvm::opt::ArgList &Args,
+                                const char *LinkingOutput) const {
+  static const char *WrappedSymbols[] = {
+    "_Znwj",
+    "_Znaj",
+    "_ZdlPv",
+    "_ZdaPv",
+    "_ZnwjRKSt9nothrow_t",
+    "_ZnajRKSt9nothrow_t",
+    "_ZdlPvRKSt9nothrow_t",
+    "_ZdaPvRKSt9nothrow_t",
+  };
+
+  const auto &ToolChain = getToolChain();
+  ArgStringList CmdArgs;
+
+  // Silence warning for "clang -g foo.o -o foo"
+  Args.ClaimAllArgs(options::OPT_g_Group);
+  // and "clang -emit-llvm foo.o -o foo"
+  Args.ClaimAllArgs(options::OPT_emit_llvm);
+  // and for "clang -w foo.o -o foo". Other warning options are already
+  // handled somewhere else.
+  Args.ClaimAllArgs(options::OPT_w);
+
+  // FIXME: -mwindows should pass --subsystem windows
+  // FIXME: -mconsole should pass --subsystem console
+
+  // FIXME: this can be disabled via -mno-use-libstdc-wrappers
+  for (const auto &Symbol : WrappedSymbols) {
+    CmdArgs.push_back("--wrap");
+    CmdArgs.push_back(Symbol);
+  }
+
+  if (Args.hasArg(options::OPT_shared))
+    CmdArgs.push_back("--shared");
+  else if (Args.hasArg(options::OPT_mdll))
+    CmdArgs.push_back("--dll");
+
+  if (Args.hasArg(options::OPT_static))
+    CmdArgs.push_back("-Bstatic");
+  else
+    CmdArgs.push_back("-Bdynamic");
+
+  if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_mdll)) {
+    CmdArgs.push_back("--enable-auto-image-base");
+
+    CmdArgs.push_back("-e");
+    CmdArgs.push_back("__cygwin_dll_entry@12");
+  }
+
+  CmdArgs.push_back("--dll-search-prefix=cyg");
+
+  if (Args.hasArg(options::OPT_rdynamic))
+    CmdArgs.push_back("--export-all-symbols");
+
+  if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_mdll)) {
+    CmdArgs.push_back("--large-address-aware");
+    CmdArgs.push_back("--tsaware");
+  }
+
+  if (Args.hasArg(options::OPT_pie))
+    CmdArgs.push_back("-pie");
+
+  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
+
+  Args.AddAllArgs(CmdArgs, options::OPT_e);
+  // FIXME: add -N, -n flags
+  Args.AddLastArg(CmdArgs, options::OPT_r);
+  Args.AddLastArg(CmdArgs, options::OPT_s);
+  Args.AddLastArg(CmdArgs, options::OPT_t);
+  Args.AddAllArgs(CmdArgs, options::OPT_u_Group);
+  Args.AddLastArg(CmdArgs, options::OPT_Z_Flag);
+
+  if (!Args.hasArg(options::OPT_nostdlib) &&
+      !Args.hasArg(options::OPT_nostartfiles)) {
+    if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_mdll)) {
+      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
+      if (Args.hasArg(options::OPT_pg))
+        CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("gcrt0.o")));
+    }
+    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o")));
+  }
+
+  Args.AddAllArgs(CmdArgs, options::OPT_L);
+
+  // FIXME: support mudflap: wrap the following:
+  // -fmudflap || -fmudflapth:
+  // static const char *WrappedStaticSymbols[] = {
+  //   "malloc", "free", "calloc", "realloc", "mmap", "mmap64", "munmap",
+  //   "alloca",
+  // };
+  // -fmudflapth:
+  // static const char *WrappedStaticSymbols[] = {
+  //   "pthread_create",
+  // };
+  // -fmudflap || -fmudflapth:
+  // static const char *WrappedSymbols[] = {
+  //   "main",
+  // };
+
+  for (const auto &Path : ToolChain.getFilePaths())
+    CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
+
+  CmdArgs.push_back("-o");
+  CmdArgs.push_back(Output.getFilename());
+
+  // FIXME: support -freopen, -ftree-parallelize-loops=*
+  // FIXME: support itm (-fgnu-tm)
+  // FIXME: support mudflap (-fmudflap || -fmudflapth) ? -export-dynamic : ""
+
+  if (Args.hasArg(options::OPT_fsplit_stack))
+    CmdArgs.push_back("--wrap=pthread_create");
+
+  if (Args.hasArg(options::OPT_fprofile_arcs) ||
+      Args.hasArg(options::OPT_fprofile_generate) ||
+      Args.hasArg(options::OPT_coverage))
+    CmdArgs.push_back("-lgcov");
+
+  if (!Args.hasArg(options::OPT_nostdlib)) {
+    if (!Args.hasArg(options::OPT_nodefaultlibs)) {
+      // FIXME: support asan, tsan
+
+      if (Args.hasArg(options::OPT_fstack_protector) ||
+          Args.hasArg(options::OPT_fstack_protector_all)) {
+        CmdArgs.push_back("-lssp_nonshared");
+        CmdArgs.push_back("-lssp");
+      }
+
+      AddLibGCC(Args, CmdArgs);
+      if (Args.hasArg(options::OPT_pg))
+        CmdArgs.push_back("-lgmon");
+      CmdArgs.push_back("-lcygwin");
+      // FIXME: -mwindows: -lgdi32 -lcomdlg32
+      CmdArgs.push_back("-ladvapi32");
+      CmdArgs.push_back("-lshell32");
+      CmdArgs.push_back("-luser32");
+      CmdArgs.push_back("-lkernel32");
+      AddLibGCC(Args, CmdArgs);
+    }
+
+    if (!Args.hasArg(options::OPT_nostartfiles)) {
+      ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs);
+      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
+    }
+  }
+
+  Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
+
+  const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
+  C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+}
+
 void minix::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
                                    const InputInfo &Output,
                                    const InputInfoList &Inputs,
index c4e6d6c829842434168315568bdd9abc5ef6663a..708715e4fd17a5609181dfd7d89d5d35e2416a61 100644 (file)
@@ -457,6 +457,24 @@ namespace gnutools {
                       const char *LinkingOutput) const override;
   };
 }
+
+namespace cygwin {
+class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+public:
+  Link(const ToolChain &TC) : Tool("cygwin::Link", "linker", TC) {}
+
+  bool hasIntegratedCPP() const override { return false; }
+  bool isLinkJob() const override { return true; }
+
+  void ConstructJob(Compilation &C, const JobAction &JA,
+                    const InputInfo &Output, const InputInfoList &Inputs,
+                    const llvm::opt::ArgList &Args,
+                    const char *LinkingOutput) const override;
+private:
+  void AddLibGCC(const llvm::opt::ArgList &Args, ArgStringList &CmdArgs) const;
+};
+}
+
   /// minix -- Directly call GNU Binutils assembler and linker
 namespace minix {
   class LLVM_LIBRARY_VISIBILITY Assemble : public Tool  {
diff --git a/test/Driver/cygwin-link.c b/test/Driver/cygwin-link.c
new file mode 100644 (file)
index 0000000..f622b88
--- /dev/null
@@ -0,0 +1,48 @@
+// RUN: %clang -### -target i686-windows-cygnus %s 2>&1 \
+// RUN:     | FileCheck %s -check-prefix CHECK-EXE -check-prefix CHECK
+
+// RUN: %clang -shared -### -target i686-windows-cygnus %s 2>&1 \
+// RUN:     | FileCheck %s -check-prefix CHECK-SHARED -check-prefix CHECK
+
+// RUN: %clang -static -### -target i686-windows-cygnus %s 2>&1 \
+// RUN:     | FileCheck %s -check-prefix CHECK-STATIC -check-prefix CHECK
+
+// CHECK: "{{.*}}ld"
+// CHECK: "--wrap" "_Znwj"
+// CHECK: "--wrap" "_Znaj"
+// CHECK: "--wrap" "_ZdlPv"
+// CHECK: "--wrap" "_ZdaPv"
+// CHECK: "--wrap" "_ZnwjRKSt9nothrow_t"
+// CHECK: "--wrap" "_ZnajRKSt9nothrow_t"
+// CHECK: "--wrap" "_ZdlPvRKSt9nothrow_t"
+// CHECK: "--wrap" "_ZdaPvRKSt9nothrow_t"
+// CHECK-SHARED: "--shared"
+// CHECK-STATIC: "-Bstatic"
+// CHECK-DYNAMIC: "-Bdynamic"
+// CHECK-EXE: "-Bdynamic"
+// CHECK-SHARED: "--enable-auto-image-base"
+// CHECK-SHARED: "-e" "__cygwin_dll_entry@12"
+// CHECK: "--dll-search-prefix=cyg"
+// CHECK-EXE: "--large-address-aware"
+// CHECK-STATIC: "--large-address-aware"
+// CHECK-EXE: "--tsaware"
+// CHECK-STATIC: "--tsaware"
+// CHECK: .o"
+// CHECK-EXE: crt0.o"
+// CHECK-STATIC: crt0.o"
+// CHECK: crtbegin.o"
+// CHECK: "-L/usr/lib"
+// CHECK: "-o"
+// CHECK-EXE: "-lgcc_s"
+// CHECK: "-lgcc"
+// CHECK-STATIC: "-lgcc_eh"
+// CHECK: "-lcygwin"
+// CHECK: "-ladvapi32"
+// CHECK: "-lshell32"
+// CHECK: "-luser32"
+// CHECK: "-lkernel32"
+// CHECK-EXE: "-lgcc_s"
+// CHECK: "-lgcc"
+// CHECK-STATIC: "-lgcc_eh"
+// CHECK: crtend.o"
+