Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -499,6 +499,8 @@ 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); } Index: lib/Basic/Targets/OSTargets.h =================================================================== --- lib/Basic/Targets/OSTargets.h +++ lib/Basic/Targets/OSTargets.h @@ -270,6 +270,29 @@ } }; +// 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 { Index: lib/Driver/CMakeLists.txt =================================================================== --- lib/Driver/CMakeLists.txt +++ lib/Driver/CMakeLists.txt @@ -47,6 +47,7 @@ ToolChains/Haiku.cpp ToolChains/HIP.cpp ToolChains/Hexagon.cpp + ToolChains/Hurd.cpp ToolChains/Linux.cpp ToolChains/MipsLinux.cpp ToolChains/MinGW.cpp Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ 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 @@ 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 @@ 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. Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -530,7 +530,8 @@ 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: Index: lib/Driver/ToolChains/Gnu.cpp =================================================================== --- lib/Driver/ToolChains/Gnu.cpp +++ lib/Driver/ToolChains/Gnu.cpp @@ -1880,7 +1880,8 @@ "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[] = { @@ -2260,6 +2261,9 @@ // 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)}}; for (auto &Suffix : Suffixes) { Index: lib/Driver/ToolChains/Hurd.h =================================================================== --- lib/Driver/ToolChains/Hurd.h +++ 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 Index: lib/Driver/ToolChains/Hurd.cpp =================================================================== --- lib/Driver/ToolChains/Hurd.cpp +++ 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"); +} Index: lib/Frontend/InitHeaderSearch.cpp =================================================================== --- lib/Frontend/InitHeaderSearch.cpp +++ lib/Frontend/InitHeaderSearch.cpp @@ -260,6 +260,7 @@ 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 @@ 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 @@ break; // Everything else continues to use this routine's logic. case llvm::Triple::Linux: + case llvm::Triple::Hurd: case llvm::Triple::Solaris: return; Index: test/Driver/hurd.c =================================================================== --- test/Driver/hurd.c +++ 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"