From 2709c8b804eb38dbdc8ae05b8fcf4f95c01b4102 Mon Sep 17 00:00:00 2001 From: Kristina Brooks Date: Thu, 29 Nov 2018 03:49:14 +0000 Subject: [PATCH] Add Hurd target to Clang driver (2/2) This adds Hurd toolchain support to Clang's driver in addition to handling translating the triple from Hurd-compatible form to the actual triple registered in LLVM. (Phabricator was stripping the empty files from the patch so I manually created them) Patch by sthibaul (Samuel Thibault) Differential Revision: https://reviews.llvm.org/D54379 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@347833 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Basic/Targets.cpp | 2 + lib/Basic/Targets/OSTargets.h | 23 +++ lib/Driver/CMakeLists.txt | 1 + lib/Driver/Driver.cpp | 11 ++ lib/Driver/ToolChains/Clang.cpp | 3 +- lib/Driver/ToolChains/Gnu.cpp | 6 +- lib/Driver/ToolChains/Hurd.cpp | 169 ++++++++++++++++++ lib/Driver/ToolChains/Hurd.h | 46 +++++ lib/Frontend/InitHeaderSearch.cpp | 3 + .../Inputs/basic_hurd_tree/include/.keep | 0 .../Inputs/basic_hurd_tree/lib/i386-gnu/.keep | 0 .../Driver/Inputs/basic_hurd_tree/lib32/.keep | 0 .../usr/include/i386-gnu/.keep | 0 .../basic_hurd_tree/usr/lib/i386-gnu/.keep | 0 .../Inputs/basic_hurd_tree/usr/lib32/.keep | 0 test/Driver/hurd.c | 62 +++++++ 16 files changed, 324 insertions(+), 2 deletions(-) create mode 100644 lib/Driver/ToolChains/Hurd.cpp create mode 100644 lib/Driver/ToolChains/Hurd.h create mode 100644 test/Driver/Inputs/basic_hurd_tree/include/.keep create mode 100644 test/Driver/Inputs/basic_hurd_tree/lib/i386-gnu/.keep create mode 100644 test/Driver/Inputs/basic_hurd_tree/lib32/.keep create mode 100644 test/Driver/Inputs/basic_hurd_tree/usr/include/i386-gnu/.keep create mode 100644 test/Driver/Inputs/basic_hurd_tree/usr/lib/i386-gnu/.keep create mode 100644 test/Driver/Inputs/basic_hurd_tree/usr/lib32/.keep create mode 100644 test/Driver/hurd.c diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 3c94a9278b..f79da4e576 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -499,6 +499,8 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, return new NaClTargetInfo(Triple, Opts); case llvm::Triple::ELFIAMCU: return new MCUX86_32TargetInfo(Triple, Opts); + case llvm::Triple::Hurd: + return new HurdTargetInfo(Triple, Opts); default: return new X86_32TargetInfo(Triple, Opts); } diff --git a/lib/Basic/Targets/OSTargets.h b/lib/Basic/Targets/OSTargets.h index 0327ff983a..1a0719d7dc 100644 --- a/lib/Basic/Targets/OSTargets.h +++ b/lib/Basic/Targets/OSTargets.h @@ -270,6 +270,29 @@ public: } }; +// Hurd target +template +class LLVM_LIBRARY_VISIBILITY HurdTargetInfo : public OSTargetInfo { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // Hurd defines; list based off of gcc output. + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__GNU__"); + Builder.defineMacro("__gnu_hurd__"); + Builder.defineMacro("__MACH__"); + Builder.defineMacro("__GLIBC__"); + Builder.defineMacro("__ELF__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } +public: + HurdTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo(Triple, Opts) {} +}; + // Minix Target template class LLVM_LIBRARY_VISIBILITY MinixTargetInfo : public OSTargetInfo { diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt index 1e6122e98c..bc96098d0a 100644 --- a/lib/Driver/CMakeLists.txt +++ b/lib/Driver/CMakeLists.txt @@ -47,6 +47,7 @@ add_clang_library(clangDriver ToolChains/Haiku.cpp ToolChains/HIP.cpp ToolChains/Hexagon.cpp + ToolChains/Hurd.cpp ToolChains/Linux.cpp ToolChains/MipsLinux.cpp ToolChains/MinGW.cpp diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 41c1da333f..3df887017d 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -26,6 +26,7 @@ #include "ToolChains/HIP.h" #include "ToolChains/Haiku.h" #include "ToolChains/Hexagon.h" +#include "ToolChains/Hurd.h" #include "ToolChains/Lanai.h" #include "ToolChains/Linux.h" #include "ToolChains/MSVC.h" @@ -402,6 +403,13 @@ static llvm::Triple computeTargetTriple(const Driver &D, llvm::Triple Target(llvm::Triple::normalize(TargetTriple)); + // GNU/Hurd's triples should have been -hurd-gnu*, but were historically made + // -gnu* only, and we can not change this, so we have to detect that case as + // being the Hurd OS. + if (TargetTriple.find("-unknown-gnu") != StringRef::npos || + TargetTriple.find("-pc-gnu") != StringRef::npos) + Target.setOSName("hurd"); + // Handle Apple-specific options available here. if (Target.isOSBinFormatMachO()) { // If an explicit Darwin arch name is given, that trumps all. @@ -4574,6 +4582,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::Contiki: TC = llvm::make_unique(*this, Target, Args); break; + case llvm::Triple::Hurd: + TC = llvm::make_unique(*this, Target, Args); + break; default: // Of these targets, Hexagon is the only one that might have // an OS of Linux, in which case it got handled above already. diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index c0f345425c..be5bd4f4a8 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -530,7 +530,8 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args, return !areOptimizationsEnabled(Args); } - if (Triple.isOSLinux() || Triple.getOS() == llvm::Triple::CloudABI) { + if (Triple.isOSLinux() || Triple.getOS() == llvm::Triple::CloudABI || + Triple.isOSHurd()) { switch (Triple.getArch()) { // Don't use a frame pointer on linux if optimizing for certain targets. case llvm::Triple::mips64: diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp index d7797d9fe5..26427fb8df 100644 --- a/lib/Driver/ToolChains/Gnu.cpp +++ b/lib/Driver/ToolChains/Gnu.cpp @@ -1880,7 +1880,8 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( "i386-linux-gnu", "i386-redhat-linux6E", "i686-redhat-linux", "i586-redhat-linux", "i386-redhat-linux", "i586-suse-linux", "i486-slackware-linux", "i686-montavista-linux", "i586-linux-gnu", - "i686-linux-android"}; + "i686-linux-android", "i386-gnu", "i486-gnu", + "i586-gnu", "i686-gnu"}; static const char *const MIPSLibDirs[] = {"/lib"}; static const char *const MIPSTriples[] = { @@ -2259,6 +2260,9 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( // FIXME: It may be worthwhile to generalize this and look for a second // triple. {"i386-linux-gnu/gcc/" + CandidateTriple.str(), "../../..", + (TargetArch == llvm::Triple::x86 && + TargetTriple.getOS() != llvm::Triple::Solaris)}, + {"i386-gnu/gcc/" + CandidateTriple.str(), "../../..", (TargetArch == llvm::Triple::x86 && TargetTriple.getOS() != llvm::Triple::Solaris)}}; diff --git a/lib/Driver/ToolChains/Hurd.cpp b/lib/Driver/ToolChains/Hurd.cpp new file mode 100644 index 0000000000..ff7b685dae --- /dev/null +++ b/lib/Driver/ToolChains/Hurd.cpp @@ -0,0 +1,169 @@ +//===--- Hurd.cpp - Hurd ToolChain Implementations --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Hurd.h" +#include "CommonArgs.h" +#include "clang/Config/config.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +using tools::addPathIfExists; + +/// Get our best guess at the multiarch triple for a target. +/// +/// Debian-based systems are starting to use a multiarch setup where they use +/// a target-triple directory in the library and header search paths. +/// Unfortunately, this triple does not align with the vanilla target triple, +/// so we provide a rough mapping here. +static std::string getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) { + if (TargetTriple.getArch() == llvm::Triple::x86) { + // We use the existence of '/lib/' as a directory to detect some + // common hurd triples that don't quite match the Clang triple for both + // 32-bit and 64-bit targets. Multiarch fixes its install triples to these + // regardless of what the actual target triple is. + if (D.getVFS().exists(SysRoot + "/lib/i386-gnu")) + return "i386-gnu"; + } + + // For most architectures, just use whatever we have rather than trying to be + // clever. + return TargetTriple.str(); +} + +static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { + // It happens that only x86 and PPC use the 'lib32' variant of oslibdir, and + // using that variant while targeting other architectures causes problems + // because the libraries are laid out in shared system roots that can't cope + // with a 'lib32' library search path being considered. So we only enable + // them when we know we may need it. + // + // FIXME: This is a bit of a hack. We should really unify this code for + // reasoning about oslibdir spellings with the lib dir spellings in the + // GCCInstallationDetector, but that is a more significant refactoring. + + if (Triple.getArch() == llvm::Triple::x86) + return "lib32"; + + return Triple.isArch32Bit() ? "lib" : "lib64"; +} + +Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + std::string SysRoot = computeSysRoot(); + path_list &Paths = getFilePaths(); + + const std::string OSLibDir = getOSLibDir(Triple, Args); + const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); + + // If we are currently running Clang inside of the requested system root, add + // its parent library paths to those searched. + // FIXME: It's not clear whether we should use the driver's installed + // directory ('Dir' below) or the ResourceDir. + if (StringRef(D.Dir).startswith(SysRoot)) { + addPathIfExists(D, D.Dir + "/../lib/" + MultiarchTriple, Paths); + addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths); + } + + addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths); + addPathIfExists(D, SysRoot + "/lib/../" + OSLibDir, Paths); + + addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths); + addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths); + + // If we are currently running Clang inside of the requested system root, add + // its parent library path to those searched. + // FIXME: It's not clear whether we should use the driver's installed + // directory ('Dir' below) or the ResourceDir. + if (StringRef(D.Dir).startswith(SysRoot)) + addPathIfExists(D, D.Dir + "/../lib", Paths); + + addPathIfExists(D, SysRoot + "/lib", Paths); + addPathIfExists(D, SysRoot + "/usr/lib", Paths); +} + +bool Hurd::HasNativeLLVMSupport() const { return true; } + +Tool *Hurd::buildLinker() const { return new tools::gnutools::Linker(*this); } + +Tool *Hurd::buildAssembler() const { + return new tools::gnutools::Assembler(*this); +} + +std::string Hurd::computeSysRoot() const { + if (!getDriver().SysRoot.empty()) + return getDriver().SysRoot; + + return std::string(); +} + +std::string Hurd::getDynamicLinker(const ArgList &Args) const { + if (getArch() == llvm::Triple::x86) + return "/lib/ld.so"; + + llvm_unreachable("unsupported architecture"); +} + +void Hurd::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + std::string SysRoot = computeSysRoot(); + + if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) + addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include"); + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "include"); + addSystemInclude(DriverArgs, CC1Args, P); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + // Check for configure-time C include directories. + StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (CIncludeDirs != "") { + SmallVector Dirs; + CIncludeDirs.split(Dirs, ":"); + for (StringRef Dir : Dirs) { + StringRef Prefix = + llvm::sys::path::is_absolute(Dir) ? StringRef(SysRoot) : ""; + addExternCSystemInclude(DriverArgs, CC1Args, Prefix + Dir); + } + return; + } + + // Lacking those, try to detect the correct set of system includes for the + // target triple. + if (getTriple().getArch() == llvm::Triple::x86) { + std::string Path = SysRoot + "/usr/include/i386-gnu"; + if (D.getVFS().exists(Path)) + addExternCSystemInclude(DriverArgs, CC1Args, Path); + } + + // Add an include of '/include' directly. This isn't provided by default by + // system GCCs, but is often used with cross-compiling GCCs, and harmless to + // add even when Clang is acting as-if it were a system compiler. + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include"); + + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); +} diff --git a/lib/Driver/ToolChains/Hurd.h b/lib/Driver/ToolChains/Hurd.h new file mode 100644 index 0000000000..d14619f0e2 --- /dev/null +++ b/lib/Driver/ToolChains/Hurd.h @@ -0,0 +1,46 @@ +//===--- Hurd.h - Hurd ToolChain Implementations ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Hurd_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Hurd_H + +#include "Gnu.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Hurd : public Generic_ELF { +public: + Hurd(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool HasNativeLLVMSupport() const override; + + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + virtual std::string computeSysRoot() const; + + virtual std::string getDynamicLinker(const llvm::opt::ArgList &Args) const; + + std::vector ExtraOpts; + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Hurd_H diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index deedb22f3e..fe6ce4d912 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -260,6 +260,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, switch (os) { case llvm::Triple::Linux: + case llvm::Triple::Hurd: case llvm::Triple::Solaris: llvm_unreachable("Include management is handled in the driver."); @@ -412,6 +413,7 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths( switch (os) { case llvm::Triple::Linux: + case llvm::Triple::Hurd: case llvm::Triple::Solaris: llvm_unreachable("Include management is handled in the driver."); break; @@ -460,6 +462,7 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang, break; // Everything else continues to use this routine's logic. case llvm::Triple::Linux: + case llvm::Triple::Hurd: case llvm::Triple::Solaris: return; diff --git a/test/Driver/Inputs/basic_hurd_tree/include/.keep b/test/Driver/Inputs/basic_hurd_tree/include/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Driver/Inputs/basic_hurd_tree/lib/i386-gnu/.keep b/test/Driver/Inputs/basic_hurd_tree/lib/i386-gnu/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Driver/Inputs/basic_hurd_tree/lib32/.keep b/test/Driver/Inputs/basic_hurd_tree/lib32/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Driver/Inputs/basic_hurd_tree/usr/include/i386-gnu/.keep b/test/Driver/Inputs/basic_hurd_tree/usr/include/i386-gnu/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Driver/Inputs/basic_hurd_tree/usr/lib/i386-gnu/.keep b/test/Driver/Inputs/basic_hurd_tree/usr/lib/i386-gnu/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Driver/Inputs/basic_hurd_tree/usr/lib32/.keep b/test/Driver/Inputs/basic_hurd_tree/usr/lib32/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Driver/hurd.c b/test/Driver/hurd.c new file mode 100644 index 0000000000..a6ca8ea337 --- /dev/null +++ b/test/Driver/hurd.c @@ -0,0 +1,62 @@ +// RUN: %clang -no-canonical-prefixes %s -### 2>&1 \ +// RUN: --target=i386-pc-gnu \ +// RUN: --sysroot=%S/Inputs/basic_hurd_tree \ +// RUN: | FileCheck --check-prefix=CHECK %s +// CHECK-NOT: warning: +// CHECK: "-cc1" +// CHECK: "-isysroot" "[[SYSROOT:[^"]+]]" +// CHECK: "-internal-isystem" "[[SYSROOT]]/usr/local/include" +// CHECK: "-internal-externc-isystem" "[[SYSROOT]]/usr/include/i386-gnu" +// CHECK: "-internal-externc-isystem" "[[SYSROOT]]/include" +// CHECK: "-internal-externc-isystem" "[[SYSROOT]]/usr/include" +// CHECK: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK: "-dynamic-linker" "/lib/ld.so" +// CHECK: "crtbegin.o" +// CHECK: "-L[[SYSROOT]]/lib/i386-gnu" +// CHECK: "-L[[SYSROOT]]/lib/../lib32" +// CHECK: "-L[[SYSROOT]]/usr/lib/i386-gnu" +// CHECK: "-L[[SYSROOT]]/usr/lib/../lib32" +// CHECK: "-L[[SYSROOT]]/lib" +// CHECK: "-L[[SYSROOT]]/usr/lib" + +// RUN: %clang -no-canonical-prefixes %s -### 2>&1 \ +// RUN: --target=i386-pc-gnu -static \ +// RUN: --sysroot=%S/Inputs/basic_hurd_tree \ +// RUN: | FileCheck --check-prefix=CHECK-STATIC %s +// CHECK-STATIC-NOT: warning: +// CHECK-STATIC: "-cc1" +// CHECK-STATIC: "-static-define" +// CHECK-STATIC: "-isysroot" "[[SYSROOT:[^"]+]]" +// CHECK-STATIC: "-internal-isystem" "[[SYSROOT]]/usr/local/include" +// CHECK-STATIC: "-internal-externc-isystem" "[[SYSROOT]]/usr/include/i386-gnu" +// CHECK-STATIC: "-internal-externc-isystem" "[[SYSROOT]]/include" +// CHECK-STATIC: "-internal-externc-isystem" "[[SYSROOT]]/usr/include" +// CHECK-STATIC: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-STATIC: "-static" +// CHECK-STATIC: "crtbeginT.o" +// CHECK-STATIC: "-L[[SYSROOT]]/lib/i386-gnu" +// CHECK-STATIC: "-L[[SYSROOT]]/lib/../lib32" +// CHECK-STATIC: "-L[[SYSROOT]]/usr/lib/i386-gnu" +// CHECK-STATIC: "-L[[SYSROOT]]/usr/lib/../lib32" +// CHECK-STATIC: "-L[[SYSROOT]]/lib" +// CHECK-STATIC: "-L[[SYSROOT]]/usr/lib" + +// RUN: %clang -no-canonical-prefixes %s -### 2>&1 \ +// RUN: --target=i386-pc-gnu -shared \ +// RUN: --sysroot=%S/Inputs/basic_hurd_tree \ +// RUN: | FileCheck --check-prefix=CHECK-SHARED %s +// CHECK-SHARED-NOT: warning: +// CHECK-SHARED: "-cc1" +// CHECK-SHARED: "-isysroot" "[[SYSROOT:[^"]+]]" +// CHECK-SHARED: "-internal-isystem" "[[SYSROOT]]/usr/local/include" +// CHECK-SHARED: "-internal-externc-isystem" "[[SYSROOT]]/usr/include/i386-gnu" +// CHECK-SHARED: "-internal-externc-isystem" "[[SYSROOT]]/include" +// CHECK-SHARED: "-internal-externc-isystem" "[[SYSROOT]]/usr/include" +// CHECK-SHARED: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-SHARED: "crtbeginS.o" +// CHECK-SHARED: "-L[[SYSROOT]]/lib/i386-gnu" +// CHECK-SHARED: "-L[[SYSROOT]]/lib/../lib32" +// CHECK-SHARED: "-L[[SYSROOT]]/usr/lib/i386-gnu" +// CHECK-SHARED: "-L[[SYSROOT]]/usr/lib/../lib32" +// CHECK-SHARED: "-L[[SYSROOT]]/lib" +// CHECK-SHARED: "-L[[SYSROOT]]/usr/lib" -- 2.40.0