]> granicus.if.org Git - clang/commitdiff
Driver: add CrossWindowsToolChain
authorSaleem Abdulrasool <compnerd@compnerd.org>
Fri, 24 Oct 2014 03:13:37 +0000 (03:13 +0000)
committerSaleem Abdulrasool <compnerd@compnerd.org>
Fri, 24 Oct 2014 03:13:37 +0000 (03:13 +0000)
This is a very basic toolchain.  It supports cross-compiling Windows (primarily
inspired by the WoA target).  It is meant to use clang with the LLVM IAS and a
binutils ld-compatible interface for the linker (eventually to be lld).  It does
not perform any "standard" GCC lookup, nor does it perform any special
adjustments given that it is expected to be used in an environment where the
user is using MSVCRT (and as such Visual Studio headers) and the Windows SDK.
The primary runtime library is expected to be compiler-rt and the C++
implementation to be libc++.

It also expects that a sysroot has been setup given the usual Unix semantics
(standard C headers in /usr/include, all the import libraries available in
/usr/lib).  It also expects that an entry point stub is present in /usr/lib
(crtbegin.obj for executables, crtbeginS.obj for shared libraries).

The entry point stub is responsible for running any GNU constructors.

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

lib/Driver/CMakeLists.txt
lib/Driver/Driver.cpp
lib/Driver/ToolChains.h
lib/Driver/Tools.cpp
lib/Driver/Tools.h
test/Driver/windows-cross.c [new file with mode: 0644]

index dfc6e091f992cadd6551a4b6797ebce1f6beabad..412840b6ea6ea06b7de903f1dfa98d9c29552540 100644 (file)
@@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS
 add_clang_library(clangDriver
   Action.cpp
   Compilation.cpp
+  CrossWindowsToolChain.cpp
   Driver.cpp
   DriverOptions.cpp
   Job.cpp
index 9fea2f405cd8001e96bf9eb80dd61d0bfcbb4aa3..cb75f2ccebe2ca4475b45a47c6bcac32da4bda16 100644 (file)
@@ -2039,6 +2039,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
         else
           TC = new toolchains::Generic_GCC(*this, Target, Args);
         break;
+      case llvm::Triple::Itanium:
+        TC = new toolchains::CrossWindowsToolChain(*this, Target, Args);
+        break;
       case llvm::Triple::MSVC:
       case llvm::Triple::UnknownEnvironment:
         TC = new toolchains::MSVCToolChain(*this, Target, Args);
index 525a7d29a4f41da0d6ceb284c3a654a9db81ff0f..d8059583563d7694f66ae2f7fb82a8d569b072a1 100644 (file)
@@ -761,6 +761,34 @@ protected:
   Tool *buildAssembler() const override;
 };
 
+class LLVM_LIBRARY_VISIBILITY CrossWindowsToolChain : public Generic_GCC {
+public:
+  CrossWindowsToolChain(const Driver &D, const llvm::Triple &T,
+                        const llvm::opt::ArgList &Args);
+
+  bool IsIntegratedAssemblerDefault() const override { return true; }
+  bool IsUnwindTablesDefault() const override;
+  bool isPICDefault() const override;
+  bool isPIEDefault() const override;
+  bool isPICDefaultForced() const override;
+
+  unsigned int GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
+    return 0;
+  }
+
+  void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+                                 llvm::opt::ArgStringList &CC1Args)
+      const override;
+  void AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+                                    llvm::opt::ArgStringList &CC1Args)
+      const override;
+  void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+                           llvm::opt::ArgStringList &CmdArgs) const override;
+
+protected:
+  Tool *buildLinker() const override;
+  Tool *buildAssembler() const override;
+};
 
 class LLVM_LIBRARY_VISIBILITY XCore : public ToolChain {
 public:
index 4a125f5a9da96613988040caeb7ee46cea1bfe79..e34fd5c9e43cc1b2accaa4aec6ab2e4942ad3fe9 100644 (file)
@@ -2138,6 +2138,14 @@ static void addClangRTLinux(
     CmdArgs.push_back("-lgcc_eh");
 }
 
+static void addClangRTWindows(const ToolChain &TC, const ArgList &Args,
+                              ArgStringList &CmdArgs) {
+  SmallString<128> LibClangRT = getCompilerRTLibDir(TC);
+  llvm::sys::path::append(LibClangRT, Twine("libclang_rt.builtins-") +
+                          getArchNameForCompilerRTLib(TC) + ".lib");
+  CmdArgs.push_back(Args.MakeArgString(LibClangRT));
+}
+
 static void addProfileRT(
     const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) {
   if (!(Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
@@ -7288,7 +7296,15 @@ static void AddRunTimeLibs(const ToolChain &TC, const Driver &D,
 
   switch(RLT) {
   case ToolChain::RLT_CompilerRT:
-    addClangRTLinux(TC, Args, CmdArgs);
+    switch (TC.getTriple().getOS()) {
+    default: llvm_unreachable("unsupported OS");
+    case llvm::Triple::Win32:
+      addClangRTWindows(TC, Args, CmdArgs);
+      break;
+    case llvm::Triple::Linux:
+      addClangRTLinux(TC, Args, CmdArgs);
+      break;
+    }
     break;
   case ToolChain::RLT_Libgcc:
     AddLibgcc(TC.getTriple(), D, CmdArgs, Args);
@@ -8114,3 +8130,181 @@ void XCore::Link::ConstructJob(Compilation &C, const JobAction &JA,
   const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc"));
   C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
 }
+
+void CrossWindows::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
+                                          const InputInfo &Output,
+                                          const InputInfoList &Inputs,
+                                          const ArgList &Args,
+                                          const char *LinkingOutput) const {
+  const auto &TC =
+      static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain());
+  ArgStringList CmdArgs;
+  const char *Exec;
+
+  switch (TC.getArch()) {
+  default: llvm_unreachable("unsupported architecture");
+  case llvm::Triple::arm:
+  case llvm::Triple::thumb:
+    break;
+  case llvm::Triple::x86:
+    CmdArgs.push_back("--32");
+    break;
+  case llvm::Triple::x86_64:
+    CmdArgs.push_back("--64");
+    break;
+  }
+
+  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+  CmdArgs.push_back("-o");
+  CmdArgs.push_back(Output.getFilename());
+
+  for (const auto &Input : Inputs)
+    CmdArgs.push_back(Input.getFilename());
+
+  const std::string Assembler = TC.GetProgramPath("as");
+  Exec = Args.MakeArgString(Assembler);
+
+  C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
+}
+
+void CrossWindows::Link::ConstructJob(Compilation &C, const JobAction &JA,
+                                      const InputInfo &Output,
+                                      const InputInfoList &Inputs,
+                                      const ArgList &Args,
+                                      const char *LinkingOutput) const {
+  const auto &TC =
+      static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain());
+  const llvm::Triple &T = TC.getTriple();
+  const Driver &D = TC.getDriver();
+  SmallString<128> EntryPoint;
+  ArgStringList CmdArgs;
+  const char *Exec;
+
+  // 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"
+  Args.ClaimAllArgs(options::OPT_w);
+  // Other warning options are already handled somewhere else.
+
+  if (!D.SysRoot.empty())
+    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+  if (Args.hasArg(options::OPT_pie))
+    CmdArgs.push_back("-pie");
+  if (Args.hasArg(options::OPT_rdynamic))
+    CmdArgs.push_back("-export-dynamic");
+  if (Args.hasArg(options::OPT_s))
+    CmdArgs.push_back("--strip-all");
+
+  CmdArgs.push_back("-m");
+  switch (TC.getArch()) {
+  default: llvm_unreachable("unsupported architecture");
+  case llvm::Triple::arm:
+  case llvm::Triple::thumb:
+    // FIXME: this is incorrect for WinCE
+    CmdArgs.push_back("thumb2pe");
+    break;
+  case llvm::Triple::x86:
+    CmdArgs.push_back("i386pe");
+    EntryPoint.append("_");
+    break;
+  case llvm::Triple::x86_64:
+    CmdArgs.push_back("i386pep");
+    break;
+  }
+
+  if (Args.hasArg(options::OPT_shared)) {
+    switch (T.getArch()) {
+    default: llvm_unreachable("unsupported architecture");
+    case llvm::Triple::arm:
+    case llvm::Triple::thumb:
+    case llvm::Triple::x86_64:
+      EntryPoint.append("_DllMainCRTStartup");
+      break;
+    case llvm::Triple::x86:
+      EntryPoint.append("_DllMainCRTStartup@12");
+      break;
+    }
+
+    CmdArgs.push_back("-shared");
+    CmdArgs.push_back("-Bdynamic");
+
+    CmdArgs.push_back("--enable-auto-image-base");
+
+    CmdArgs.push_back("--entry");
+    CmdArgs.push_back(Args.MakeArgString(EntryPoint));
+  } else {
+    EntryPoint.append("mainCRTStartup");
+
+    CmdArgs.push_back(Args.hasArg(options::OPT_static) ? "-Bstatic"
+                                                       : "-Bdynamic");
+
+    if (!Args.hasArg(options::OPT_nostdlib) &&
+        !Args.hasArg(options::OPT_nostartfiles)) {
+      CmdArgs.push_back("--entry");
+      CmdArgs.push_back(Args.MakeArgString(EntryPoint));
+    }
+
+    // FIXME: handle subsystem
+  }
+
+  // NOTE: deal with multiple definitions on Windows (e.g. COMDAT)
+  CmdArgs.push_back("--allow-multiple-definitions");
+
+  CmdArgs.push_back("-o");
+  CmdArgs.push_back(Output.getFilename());
+
+  if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_rdynamic)) {
+    SmallString<261> ImpLib(Output.getFilename());
+    llvm::sys::path::replace_extension(ImpLib, ".lib");
+
+    CmdArgs.push_back("--out-implib");
+    CmdArgs.push_back(Args.MakeArgString(ImpLib));
+  }
+
+  if (!Args.hasArg(options::OPT_nostdlib) &&
+      !Args.hasArg(options::OPT_nostartfiles)) {
+    const std::string CRTPath(D.SysRoot + "/usr/lib/");
+    const char *CRTBegin;
+
+    CRTBegin =
+        Args.hasArg(options::OPT_shared) ? "crtbeginS.obj" : "crtbegin.obj";
+    CmdArgs.push_back(Args.MakeArgString(CRTPath + CRTBegin));
+  }
+
+  Args.AddAllArgs(CmdArgs, options::OPT_L);
+
+  const auto &Paths = TC.getFilePaths();
+  for (const auto &Path : Paths)
+    CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
+
+  AddLinkerInputs(TC, Inputs, Args, CmdArgs);
+
+  if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) &&
+      !Args.hasArg(options::OPT_nodefaultlibs)) {
+    bool StaticCXX = Args.hasArg(options::OPT_static_libstdcxx) &&
+                     !Args.hasArg(options::OPT_static);
+    if (StaticCXX)
+      CmdArgs.push_back("-Bstatic");
+    TC.AddCXXStdlibLibArgs(Args, CmdArgs);
+    if (StaticCXX)
+      CmdArgs.push_back("-Bdynamic");
+  }
+
+  if (!Args.hasArg(options::OPT_nostdlib)) {
+    if (!Args.hasArg(options::OPT_nodefaultlibs)) {
+      // TODO handle /MT[d] /MD[d]
+      CmdArgs.push_back("-lmsvcrt");
+      AddRunTimeLibs(TC, D, CmdArgs, Args);
+    }
+  }
+
+  const std::string Linker = TC.GetProgramPath("ld");
+  Exec = Args.MakeArgString(Linker);
+
+  C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
+}
+
index 8ab145652bb7993a5fd87c50deed736c260dea00..59af8a0ec97823e70dc8a6eeace3e4c5ed092b1d 100644 (file)
@@ -645,6 +645,32 @@ namespace XCore {
   };
 } // end namespace XCore.
 
+namespace CrossWindows {
+class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
+public:
+  Assemble(const ToolChain &TC) : Tool("CrossWindows::Assemble", "as", TC) { }
+
+  bool hasIntegratedCPP() const override { return false; }
+
+  void ConstructJob(Compilation &C, const JobAction &JA,
+                    const InputInfo &Output, const InputInfoList &Inputs,
+                    const llvm::opt::ArgList &TCArgs,
+                    const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+public:
+  Link(const ToolChain &TC) : Tool("CrossWindows::Link", "ld", TC, RF_Full) {}
+
+  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 &TCArgs,
+                    const char *LinkingOutput) const override;
+};
+}
 
 } // end namespace toolchains
 } // end namespace driver
diff --git a/test/Driver/windows-cross.c b/test/Driver/windows-cross.c
new file mode 100644 (file)
index 0000000..6fe3a36
--- /dev/null
@@ -0,0 +1,40 @@
+// RUN: %clang -### -target armv7-windows-itanium -o /dev/null %s 2>&1 \
+// RUN:   | FileCheck %s --check-prefix CHECK-BASIC
+
+// CHECK-BASIC: ld" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definitions" "-o" "/dev/null" "/usr/lib/crtbegin.obj" "-L/usr/lib" "-L/usr/lib/gcc" "{{.*}}.o" "-lmsvcrt" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+
+// RUN: %clang -### -target armv7-windows-itanium -rtlib=compiler-rt -o /dev/null %s 2>&1 \
+// RUN:   | FileCheck %s --check-prefix CHECK-RTLIB
+
+// CHECK-RTLIB: ld" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definitions" "-o" "/dev/null" "/usr/lib/crtbegin.obj" "-L/usr/lib" "-L/usr/lib/gcc" "{{.*}}.o" "-lmsvcrt" "{{.*}}/libclang_rt.builtins-arm.lib"
+
+// RUN: %clang -### -target armv7-windows-itanium --sysroot /sysroot/Windows/ARM/8.1 -rtlib=compiler-rt -o /dev/null %s 2>&1 \
+// RUN:   | FileCheck %s --check-prefix CHECK-SYSROOT
+
+// CHECK-SYSROOT: ld" "--sysroot=/sysroot/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definitions" "-o" "/dev/null" "/sysroot/Windows/ARM/8.1/usr/lib/crtbegin.obj" "-L/sysroot/Windows/ARM/8.1/usr/lib" "-L/sysroot/Windows/ARM/8.1/usr/lib/gcc" "{{.*}}.o" "-lmsvcrt" "{{.*}}/libclang_rt.builtins-arm.lib"
+
+// RUN: %clang -### -target armv7-windows-itanium --sysroot /sysroot/Windows/ARM/8.1 -rtlib=compiler-rt -stdlib=libc++ -o /dev/null %s 2>&1 \
+// RUN:   | FileCheck %s --check-prefix CHECK-C-LIBCXX
+
+// CHECK-C-LIBCXX: ld" "--sysroot=/sysroot/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definitions" "-o" "/dev/null" "/sysroot/Windows/ARM/8.1/usr/lib/crtbegin.obj" "{{.*}}.o" "-lmsvcrt" "{{.*}}/libclang_rt.builtins-arm.lib"
+
+// RUN: %clangxx -### -target armv7-windows-itanium --sysroot /sysroot/Windows/ARM/8.1 -rtlib=compiler-rt -stdlib=libc++ -o /dev/null %s 2>&1 \
+// RUN:   | FileCheck %s --check-prefix CHECK-LIBCXX
+
+// CHECK-LIBCXX: ld" "--sysroot=/sysroot/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definitions" "-o" "/dev/null" "/sysroot/Windows/ARM/8.1/usr/lib/crtbegin.obj" "{{.*}}.o" "-lc++" "-lmsvcrt" "{{.*}}/libclang_rt.builtins-arm.lib"
+
+// RUN: %clang -### -target armv7-windows-itanium --sysroot /sysroot/Windows/ARM/8.1 -shared -rtlib=compiler-rt -stdlib=libc++ -o shared.dll %s 2>&1 \
+// RUN:   | FileCheck %s --check-prefix CHECK-SHARED
+
+// CHECK-SHARED: ld" "--sysroot=/sysroot/Windows/ARM/8.1" "-m" "thumb2pe" "-shared" "-Bdynamic" "--enable-auto-image-base" "--entry" "_DllMainCRTStartup" "--allow-multiple-definitions" "-o" "shared.dll" "--out-implib" "shared.lib" "/sysroot/Windows/ARM/8.1/usr/lib/crtbeginS.obj" "{{.*}}.o" "-lmsvcrt" "{{.*}}/libclang_rt.builtins-arm.lib"
+
+// RUN: %clang -### -target armv7-windows-itanium --sysroot /sysroot/Windows/ARM/8.1 -shared -rtlib=compiler-rt -stdlib=libc++ -nostartfiles -o shared.dll %s 2>&1 \
+// RUN:   | FileCheck %s --check-prefix CHECK-NOSTARTFILES
+
+// CHECK-NOSTARTFILES: ld" "--sysroot=/sysroot/Windows/ARM/8.1" "-m" "thumb2pe" "-shared" "-Bdynamic" "--enable-auto-image-base" "--entry" "_DllMainCRTStartup" "--allow-multiple-definitions" "-o" "shared.dll" "--out-implib" "shared.lib" "{{.*}}.o" "-lmsvcrt" "{{.*}}/libclang_rt.builtins-arm.lib"
+
+// RUN: %clang -### -target armv7-windows-itanium --sysroot /sysroot/Windows/ARM/8.1 -shared -rtlib=compiler-rt -stdlib=libc++ -nostartfiles -nodefaultlibs -o shared.dll %s 2>&1 \
+// RUN:   | FileCheck %s --check-prefix CHECK-STANDALONE
+
+// CHECK-STANDALONE: ld" "--sysroot=/sysroot/Windows/ARM/8.1" "-m" "thumb2pe" "-shared" "-Bdynamic" "--enable-auto-image-base" "--entry" "_DllMainCRTStartup" "--allow-multiple-definitions" "-o" "shared.dll" "--out-implib" "shared.lib" "{{.*}}.o"
+