diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp | 1541 |
1 files changed, 1106 insertions, 435 deletions
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp index b568593..b46f69d 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp @@ -10,6 +10,7 @@ #include "ToolChains.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" +#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" @@ -27,26 +28,33 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" #include "llvm/Support/Program.h" - -// FIXME: This needs to be listed last until we fix the broken include guards -// in these files and the LLVM config.h files. -#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX - +#include "llvm/Support/raw_ostream.h" #include <cstdlib> // ::getenv +#include <system_error> using namespace clang::driver; using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; -/// Darwin - Darwin tool chain for i386 and x86_64. +MachO::MachO(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : ToolChain(D, Triple, Args) { + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != getDriver().Dir) + getProgramPaths().push_back(getDriver().Dir); -Darwin::Darwin(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) - : ToolChain(D, Triple, Args), TargetInitialized(false) -{ + // We expect 'as', 'ld', etc. to be adjacent to our install dir. + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != getDriver().Dir) + getProgramPaths().push_back(getDriver().Dir); +} + +/// Darwin - Darwin tool chain for i386 and x86_64. +Darwin::Darwin(const Driver & D, const llvm::Triple & Triple, + const ArgList & Args) + : MachO(D, Triple, Args), TargetInitialized(false) { // Compute the initial Darwin version from the triple unsigned Major, Minor, Micro; if (!Triple.getMacOSXVersion(Major, Minor, Micro)) @@ -67,7 +75,7 @@ Darwin::Darwin(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) << Major << '.' << Minor << '.' << Micro; } -types::ID Darwin::LookupTypeForExtension(const char *Ext) const { +types::ID MachO::LookupTypeForExtension(const char *Ext) const { types::ID Ty = types::lookupTypeForExtension(Ext); // Darwin always preprocesses assembly files (unless -x is used explicitly). @@ -77,13 +85,13 @@ types::ID Darwin::LookupTypeForExtension(const char *Ext) const { return Ty; } -bool Darwin::HasNativeLLVMSupport() const { +bool MachO::HasNativeLLVMSupport() const { return true; } /// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0. ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const { - if (isTargetIPhoneOS()) + if (isTargetIOSBased()) return ObjCRuntime(ObjCRuntime::iOS, TargetVersion); if (isNonFragile) return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion); @@ -92,10 +100,12 @@ ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const { /// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2. bool Darwin::hasBlocksRuntime() const { - if (isTargetIPhoneOS()) + if (isTargetIOSBased()) return !isIPhoneOSVersionLT(3, 2); - else + else { + assert(isTargetMacOS() && "unexpected darwin target"); return !isMacosxVersionLT(10, 6); + } } static const char *GetArmArchForMArch(StringRef Value) { @@ -109,11 +119,10 @@ static const char *GetArmArchForMArch(StringRef Value) { .Cases("armv7a", "armv7-a", "armv7") .Cases("armv7r", "armv7-r", "armv7") .Cases("armv7em", "armv7e-m", "armv7em") - .Cases("armv7f", "armv7-f", "armv7f") .Cases("armv7k", "armv7-k", "armv7k") .Cases("armv7m", "armv7-m", "armv7m") .Cases("armv7s", "armv7-s", "armv7s") - .Default(0); + .Default(nullptr); } static const char *GetArmArchForMCpu(StringRef Value) { @@ -124,17 +133,27 @@ static const char *GetArmArchForMCpu(StringRef Value) { .Case("xscale", "xscale") .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "arm1176jzf-s", "armv6") .Case("cortex-m0", "armv6m") - .Cases("cortex-a5", "cortex-a7", "cortex-a8", "armv7") - .Cases("cortex-a9", "cortex-a12", "cortex-a15", "armv7") + .Cases("cortex-a5", "cortex-a7", "cortex-a8", "cortex-a9-mp", "armv7") + .Cases("cortex-a9", "cortex-a12", "cortex-a15", "krait", "armv7") .Cases("cortex-r4", "cortex-r5", "armv7r") - .Case("cortex-a9-mp", "armv7f") .Case("cortex-m3", "armv7m") .Case("cortex-m4", "armv7em") .Case("swift", "armv7s") - .Default(0); + .Default(nullptr); +} + +static bool isSoftFloatABI(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, + options::OPT_mfloat_abi_EQ); + if (!A) + return false; + + return A->getOption().matches(options::OPT_msoft_float) || + (A->getOption().matches(options::OPT_mfloat_abi_EQ) && + A->getValue() == StringRef("soft")); } -StringRef Darwin::getDarwinArchName(const ArgList &Args) const { +StringRef MachO::getMachOArchName(const ArgList &Args) const { switch (getTriple().getArch()) { default: return getArchName(); @@ -157,6 +176,17 @@ StringRef Darwin::getDarwinArchName(const ArgList &Args) const { Darwin::~Darwin() { } +MachO::~MachO() { +} + + +std::string MachO::ComputeEffectiveClangTriple(const ArgList &Args, + types::ID InputType) const { + llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); + + return Triple.getTriple(); +} + std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const { llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); @@ -166,25 +196,17 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, if (!isTargetInitialized()) return Triple.getTriple(); - if (Triple.getArchName() == "thumbv6m" || - Triple.getArchName() == "thumbv7m" || - Triple.getArchName() == "thumbv7em") { - // OS is ios or macosx unless it's the v6m or v7m. - Triple.setOS(llvm::Triple::Darwin); - Triple.setEnvironment(llvm::Triple::EABI); - } else { - SmallString<16> Str; - Str += isTargetIPhoneOS() ? "ios" : "macosx"; - Str += getTargetVersion().getAsString(); - Triple.setOSName(Str); - } + SmallString<16> Str; + Str += isTargetIOSBased() ? "ios" : "macosx"; + Str += getTargetVersion().getAsString(); + Triple.setOSName(Str); return Triple.getTriple(); } void Generic_ELF::anchor() {} -Tool *Darwin::getTool(Action::ActionClass AC) const { +Tool *MachO::getTool(Action::ActionClass AC) const { switch (AC) { case Action::LipoJobClass: if (!Lipo) @@ -194,7 +216,7 @@ Tool *Darwin::getTool(Action::ActionClass AC) const { if (!Dsymutil) Dsymutil.reset(new tools::darwin::Dsymutil(*this)); return Dsymutil.get(); - case Action::VerifyJobClass: + case Action::VerifyDebugInfoJobClass: if (!VerifyDebug) VerifyDebug.reset(new tools::darwin::VerifyDebug(*this)); return VerifyDebug.get(); @@ -203,30 +225,50 @@ Tool *Darwin::getTool(Action::ActionClass AC) const { } } -Tool *Darwin::buildLinker() const { +Tool *MachO::buildLinker() const { return new tools::darwin::Link(*this); } -Tool *Darwin::buildAssembler() const { +Tool *MachO::buildAssembler() const { return new tools::darwin::Assemble(*this); } DarwinClang::DarwinClang(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) - : Darwin(D, Triple, Args) -{ - getProgramPaths().push_back(getDriver().getInstalledDir()); - if (getDriver().getInstalledDir() != getDriver().Dir) - getProgramPaths().push_back(getDriver().Dir); + : Darwin(D, Triple, Args) { +} - // We expect 'as', 'ld', etc. to be adjacent to our install dir. - getProgramPaths().push_back(getDriver().getInstalledDir()); - if (getDriver().getInstalledDir() != getDriver().Dir) - getProgramPaths().push_back(getDriver().Dir); +void DarwinClang::addClangWarningOptions(ArgStringList &CC1Args) const { + // For iOS, 64-bit, promote certain warnings to errors. + if (!isTargetMacOS() && getTriple().isArch64Bit()) { + // Always enable -Wdeprecated-objc-isa-usage and promote it + // to an error. + CC1Args.push_back("-Wdeprecated-objc-isa-usage"); + CC1Args.push_back("-Werror=deprecated-objc-isa-usage"); + + // Also error about implicit function declarations, as that + // can impact calling conventions. + CC1Args.push_back("-Werror=implicit-function-declaration"); + } +} + +/// \brief Determine whether Objective-C automated reference counting is +/// enabled. +static bool isObjCAutoRefCount(const ArgList &Args) { + return Args.hasFlag(options::OPT_fobjc_arc, options::OPT_fno_objc_arc, false); } void DarwinClang::AddLinkARCArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + // Avoid linking compatibility stubs on i386 mac. + if (isTargetMacOS() && getArch() == llvm::Triple::x86) + return; + + ObjCRuntime runtime = getDefaultObjCRuntime(/*nonfragile*/ true); + + if ((runtime.hasNativeARC() || !isObjCAutoRefCount(Args)) && + runtime.hasSubscripting()) + return; CmdArgs.push_back("-force_load"); SmallString<128> P(getDriver().ClangExecutable); @@ -245,12 +287,12 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args, CmdArgs.push_back(Args.MakeArgString(P)); } -void DarwinClang::AddLinkRuntimeLib(const ArgList &Args, - ArgStringList &CmdArgs, - const char *DarwinStaticLib, - bool AlwaysLink) const { +void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, + StringRef DarwinStaticLib, bool AlwaysLink, + bool IsEmbedded) const { SmallString<128> P(getDriver().ResourceDir); - llvm::sys::path::append(P, "lib", "darwin", DarwinStaticLib); + llvm::sys::path::append(P, "lib", IsEmbedded ? "macho_embedded" : "darwin", + DarwinStaticLib); // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build (unless @@ -290,14 +332,14 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, // If we are building profile support, link that library in. if (Args.hasArg(options::OPT_fprofile_arcs) || Args.hasArg(options::OPT_fprofile_generate) || + Args.hasArg(options::OPT_fprofile_instr_generate) || Args.hasArg(options::OPT_fcreate_profile) || Args.hasArg(options::OPT_coverage)) { // Select the appropriate runtime library for the target. - if (isTargetIPhoneOS()) { + if (isTargetIOSBased()) AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.profile_ios.a"); - } else { + else AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.profile_osx.a"); - } } const SanitizerArgs &Sanitize = getSanitizerArgs(); @@ -305,10 +347,11 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, // Add Ubsan runtime library, if required. if (Sanitize.needsUbsanRt()) { // FIXME: Move this check to SanitizerArgs::filterUnsupportedKinds. - if (isTargetIPhoneOS()) { + if (isTargetIOSBased()) { getDriver().Diag(diag::err_drv_clang_unsupported_per_platform) << "-fsanitize=undefined"; } else { + assert(isTargetMacOS() && "unexpected non OS X target"); AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ubsan_osx.a", true); // The Ubsan runtime library requires C++. @@ -320,7 +363,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, // should not be linked with the runtime library. if (Sanitize.needsAsanRt()) { // FIXME: Move this check to SanitizerArgs::filterUnsupportedKinds. - if (isTargetIPhoneOS() && !isTargetIOSSimulator()) { + if (isTargetIPhoneOS()) { getDriver().Diag(diag::err_drv_clang_unsupported_per_platform) << "-fsanitize=address"; } else { @@ -348,16 +391,19 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, CmdArgs.push_back("-lSystem"); // Select the dynamic runtime library and the target specific static library. - if (isTargetIPhoneOS()) { + if (isTargetIOSBased()) { // If we are compiling as iOS / simulator, don't attempt to link libgcc_s.1, // it never went into the SDK. // Linking against libgcc_s.1 isn't needed for iOS 5.0+ - if (isIPhoneOSVersionLT(5, 0) && !isTargetIOSSimulator()) + if (isIPhoneOSVersionLT(5, 0) && !isTargetIOSSimulator() && + (getTriple().getArch() != llvm::Triple::arm64 && + getTriple().getArch() != llvm::Triple::aarch64)) CmdArgs.push_back("-lgcc_s.1"); // We currently always need a static runtime library for iOS. AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ios.a"); } else { + assert(isTargetMacOS() && "unexpected non MacOS platform"); // The dynamic runtime library was merged with libSystem for 10.6 and // beyond; only 10.4 and 10.5 need an additional runtime library. if (isMacosxVersionLT(10, 5)) @@ -400,7 +446,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { if (llvm::sys::path::is_absolute(env) && llvm::sys::fs::exists(env) && StringRef(env) != "/") { Args.append(Args.MakeSeparateArg( - 0, Opts.getOption(options::OPT_isysroot), env)); + nullptr, Opts.getOption(options::OPT_isysroot), env)); } } } @@ -414,12 +460,12 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { getDriver().Diag(diag::err_drv_argument_not_allowed_with) << OSXVersion->getAsString(Args) << (iOSVersion ? iOSVersion : iOSSimVersion)->getAsString(Args); - iOSVersion = iOSSimVersion = 0; + iOSVersion = iOSSimVersion = nullptr; } else if (iOSVersion && iOSSimVersion) { getDriver().Diag(diag::err_drv_argument_not_allowed_with) << iOSVersion->getAsString(Args) << iOSSimVersion->getAsString(Args); - iOSSimVersion = 0; + iOSSimVersion = nullptr; } else if (!OSXVersion && !iOSVersion && !iOSSimVersion) { // If no deployment target was specified on the command line, check for // environment defines. @@ -440,7 +486,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { StringRef first, second; StringRef isysroot = A->getValue(); - llvm::tie(first, second) = isysroot.split(StringRef("SDKs/iPhoneOS")); + std::tie(first, second) = isysroot.split(StringRef("SDKs/iPhoneOS")); if (second != "") iOSTarget = second.substr(0,3); } @@ -448,9 +494,10 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { // If no OSX or iOS target has been specified and we're compiling for armv7, // go ahead as assume we're targeting iOS. + StringRef MachOArchName = getMachOArchName(Args); if (OSXTarget.empty() && iOSTarget.empty() && - (getDarwinArchName(Args) == "armv7" || - getDarwinArchName(Args) == "armv7s")) + (MachOArchName == "armv7" || MachOArchName == "armv7s" || + MachOArchName == "arm64")) iOSTarget = iOSVersionMin; // Handle conflicting deployment targets @@ -469,6 +516,8 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { // default platform. if (!OSXTarget.empty() && !iOSTarget.empty()) { if (getTriple().getArch() == llvm::Triple::arm || + getTriple().getArch() == llvm::Triple::arm64 || + getTriple().getArch() == llvm::Triple::aarch64 || getTriple().getArch() == llvm::Triple::thumb) OSXTarget = ""; else @@ -477,25 +526,36 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { if (!OSXTarget.empty()) { const Option O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); - OSXVersion = Args.MakeJoinedArg(0, O, OSXTarget); + OSXVersion = Args.MakeJoinedArg(nullptr, O, OSXTarget); Args.append(OSXVersion); } else if (!iOSTarget.empty()) { const Option O = Opts.getOption(options::OPT_miphoneos_version_min_EQ); - iOSVersion = Args.MakeJoinedArg(0, O, iOSTarget); + iOSVersion = Args.MakeJoinedArg(nullptr, O, iOSTarget); Args.append(iOSVersion); } else if (!iOSSimTarget.empty()) { const Option O = Opts.getOption( options::OPT_mios_simulator_version_min_EQ); - iOSSimVersion = Args.MakeJoinedArg(0, O, iOSSimTarget); + iOSSimVersion = Args.MakeJoinedArg(nullptr, O, iOSSimTarget); Args.append(iOSSimVersion); - } else { + } else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" && + MachOArchName != "armv7em") { // Otherwise, assume we are targeting OS X. const Option O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); - OSXVersion = Args.MakeJoinedArg(0, O, MacosxVersionMin); + OSXVersion = Args.MakeJoinedArg(nullptr, O, MacosxVersionMin); Args.append(OSXVersion); } } + DarwinPlatformKind Platform; + if (OSXVersion) + Platform = MacOS; + else if (iOSVersion) + Platform = IPhoneOS; + else if (iOSSimVersion) + Platform = IPhoneOSSimulator; + else + llvm_unreachable("Unable to infer Darwin variant"); + // Reject invalid architecture combinations. if (iOSSimVersion && (getTriple().getArch() != llvm::Triple::x86 && getTriple().getArch() != llvm::Triple::x86_64)) { @@ -506,14 +566,14 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { // Set the tool chain target information. unsigned Major, Minor, Micro; bool HadExtra; - if (OSXVersion) { + if (Platform == MacOS) { assert((!iOSVersion && !iOSSimVersion) && "Unknown target platform!"); if (!Driver::GetReleaseVersion(OSXVersion->getValue(), Major, Minor, Micro, HadExtra) || HadExtra || Major != 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << OSXVersion->getAsString(Args); - } else { + } else if (Platform == IPhoneOS || Platform == IPhoneOSSimulator) { const Arg *Version = iOSVersion ? iOSVersion : iOSSimVersion; assert(Version && "Unknown target platform!"); if (!Driver::GetReleaseVersion(Version->getValue(), Major, Minor, @@ -521,9 +581,8 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { Major >= 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << Version->getAsString(Args); - } - - bool IsIOSSim = bool(iOSSimVersion); + } else + llvm_unreachable("unknown kind of Darwin platform"); // In GCC, the simulator historically was treated as being OS X in some // contexts, like determining the link logic, despite generally being called @@ -531,9 +590,9 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { // simulator as iOS + x86, and treat it differently in a few contexts. if (iOSVersion && (getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64)) - IsIOSSim = true; + Platform = IPhoneOSSimulator; - setTarget(/*IsIPhoneOS=*/ !OSXVersion, Major, Minor, Micro, IsIOSSim); + setTarget(Platform, Major, Minor, Micro); } void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, @@ -594,6 +653,8 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args, // Use the newer cc_kext for iOS ARM after 6.0. if (!isTargetIPhoneOS() || isTargetIOSSimulator() || + getTriple().getArch() == llvm::Triple::arm64 || + getTriple().getArch() == llvm::Triple::aarch64 || !isIPhoneOSVersionLT(6, 0)) { llvm::sys::path::append(P, "libclang_rt.cc_kext.a"); } else { @@ -606,8 +667,8 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args, CmdArgs.push_back(Args.MakeArgString(P.str())); } -DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, - const char *BoundArch) const { +DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args, + const char *BoundArch) const { DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); const OptTable &Opts = getDriver().getOpts(); @@ -618,24 +679,21 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, // have something that works, we should reevaluate each translation // and try to push it down into tool specific logic. - for (ArgList::const_iterator it = Args.begin(), - ie = Args.end(); it != ie; ++it) { - Arg *A = *it; - + for (Arg *A : Args) { if (A->getOption().matches(options::OPT_Xarch__)) { // Skip this argument unless the architecture matches either the toolchain // triple arch, or the arch being bound. llvm::Triple::ArchType XarchArch = - tools::darwin::getArchTypeForDarwinArchName(A->getValue(0)); + tools::darwin::getArchTypeForMachOArchName(A->getValue(0)); if (!(XarchArch == getArch() || (BoundArch && XarchArch == - tools::darwin::getArchTypeForDarwinArchName(BoundArch)))) + tools::darwin::getArchTypeForMachOArchName(BoundArch)))) continue; Arg *OriginalArg = A; unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); unsigned Prev = Index; - Arg *XarchArg = Opts.ParseOneArg(Args, Index); + std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index)); // If the argument parsing failed or more than one argument was // consumed, the -Xarch_ argument's parameter tried to consume @@ -656,8 +714,8 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, } XarchArg->setBaseArg(A); - A = XarchArg; + A = XarchArg.release(); DAL->AddSynthesizedArg(A); // Linker input arguments require custom handling. The problem is that we @@ -741,7 +799,8 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, if (getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64) if (!Args.hasArgNoClaim(options::OPT_mtune_EQ)) - DAL->AddJoinedArg(0, Opts.getOption(options::OPT_mtune_EQ), "core2"); + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mtune_EQ), + "core2"); // Add the arch options based on the particular spelling of -arch, to match // how the driver driver works. @@ -755,89 +814,114 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, if (Name == "ppc") ; else if (Name == "ppc601") - DAL->AddJoinedArg(0, MCpu, "601"); + DAL->AddJoinedArg(nullptr, MCpu, "601"); else if (Name == "ppc603") - DAL->AddJoinedArg(0, MCpu, "603"); + DAL->AddJoinedArg(nullptr, MCpu, "603"); else if (Name == "ppc604") - DAL->AddJoinedArg(0, MCpu, "604"); + DAL->AddJoinedArg(nullptr, MCpu, "604"); else if (Name == "ppc604e") - DAL->AddJoinedArg(0, MCpu, "604e"); + DAL->AddJoinedArg(nullptr, MCpu, "604e"); else if (Name == "ppc750") - DAL->AddJoinedArg(0, MCpu, "750"); + DAL->AddJoinedArg(nullptr, MCpu, "750"); else if (Name == "ppc7400") - DAL->AddJoinedArg(0, MCpu, "7400"); + DAL->AddJoinedArg(nullptr, MCpu, "7400"); else if (Name == "ppc7450") - DAL->AddJoinedArg(0, MCpu, "7450"); + DAL->AddJoinedArg(nullptr, MCpu, "7450"); else if (Name == "ppc970") - DAL->AddJoinedArg(0, MCpu, "970"); + DAL->AddJoinedArg(nullptr, MCpu, "970"); else if (Name == "ppc64" || Name == "ppc64le") - DAL->AddFlagArg(0, Opts.getOption(options::OPT_m64)); + DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64)); else if (Name == "i386") ; else if (Name == "i486") - DAL->AddJoinedArg(0, MArch, "i486"); + DAL->AddJoinedArg(nullptr, MArch, "i486"); else if (Name == "i586") - DAL->AddJoinedArg(0, MArch, "i586"); + DAL->AddJoinedArg(nullptr, MArch, "i586"); else if (Name == "i686") - DAL->AddJoinedArg(0, MArch, "i686"); + DAL->AddJoinedArg(nullptr, MArch, "i686"); else if (Name == "pentium") - DAL->AddJoinedArg(0, MArch, "pentium"); + DAL->AddJoinedArg(nullptr, MArch, "pentium"); else if (Name == "pentium2") - DAL->AddJoinedArg(0, MArch, "pentium2"); + DAL->AddJoinedArg(nullptr, MArch, "pentium2"); else if (Name == "pentpro") - DAL->AddJoinedArg(0, MArch, "pentiumpro"); + DAL->AddJoinedArg(nullptr, MArch, "pentiumpro"); else if (Name == "pentIIm3") - DAL->AddJoinedArg(0, MArch, "pentium2"); + DAL->AddJoinedArg(nullptr, MArch, "pentium2"); else if (Name == "x86_64") - DAL->AddFlagArg(0, Opts.getOption(options::OPT_m64)); + DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64)); else if (Name == "x86_64h") { - DAL->AddFlagArg(0, Opts.getOption(options::OPT_m64)); - DAL->AddJoinedArg(0, MArch, "x86_64h"); + DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64)); + DAL->AddJoinedArg(nullptr, MArch, "x86_64h"); } else if (Name == "arm") - DAL->AddJoinedArg(0, MArch, "armv4t"); + DAL->AddJoinedArg(nullptr, MArch, "armv4t"); else if (Name == "armv4t") - DAL->AddJoinedArg(0, MArch, "armv4t"); + DAL->AddJoinedArg(nullptr, MArch, "armv4t"); else if (Name == "armv5") - DAL->AddJoinedArg(0, MArch, "armv5tej"); + DAL->AddJoinedArg(nullptr, MArch, "armv5tej"); else if (Name == "xscale") - DAL->AddJoinedArg(0, MArch, "xscale"); + DAL->AddJoinedArg(nullptr, MArch, "xscale"); else if (Name == "armv6") - DAL->AddJoinedArg(0, MArch, "armv6k"); + DAL->AddJoinedArg(nullptr, MArch, "armv6k"); else if (Name == "armv6m") - DAL->AddJoinedArg(0, MArch, "armv6m"); + DAL->AddJoinedArg(nullptr, MArch, "armv6m"); else if (Name == "armv7") - DAL->AddJoinedArg(0, MArch, "armv7a"); + DAL->AddJoinedArg(nullptr, MArch, "armv7a"); else if (Name == "armv7em") - DAL->AddJoinedArg(0, MArch, "armv7em"); - else if (Name == "armv7f") - DAL->AddJoinedArg(0, MArch, "armv7f"); + DAL->AddJoinedArg(nullptr, MArch, "armv7em"); else if (Name == "armv7k") - DAL->AddJoinedArg(0, MArch, "armv7k"); + DAL->AddJoinedArg(nullptr, MArch, "armv7k"); else if (Name == "armv7m") - DAL->AddJoinedArg(0, MArch, "armv7m"); + DAL->AddJoinedArg(nullptr, MArch, "armv7m"); else if (Name == "armv7s") - DAL->AddJoinedArg(0, MArch, "armv7s"); - - else - llvm_unreachable("invalid Darwin arch"); + DAL->AddJoinedArg(nullptr, MArch, "armv7s"); } + return DAL; +} + +void MachO::AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + // Embedded targets are simple at the moment, not supporting sanitizers and + // with different libraries for each member of the product { static, PIC } x + // { hard-float, soft-float } + llvm::SmallString<32> CompilerRT = StringRef("libclang_rt."); + CompilerRT += + tools::arm::getARMFloatABI(getDriver(), Args, getTriple()) == "hard" + ? "hard" + : "soft"; + CompilerRT += Args.hasArg(options::OPT_fPIC) ? "_pic.a" : "_static.a"; + + AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, false, true); +} + + +DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, + const char *BoundArch) const { + // First get the generic Apple args, before moving onto Darwin-specific ones. + DerivedArgList *DAL = MachO::TranslateArgs(Args, BoundArch); + const OptTable &Opts = getDriver().getOpts(); + + // If no architecture is bound, none of the translations here are relevant. + if (!BoundArch) + return DAL; + // Add an explicit version min argument for the deployment target. We do this // after argument translation because -Xarch_ arguments may add a version min // argument. - if (BoundArch) - AddDeploymentTarget(*DAL); + AddDeploymentTarget(*DAL); // For iOS 6, undo the translation to add -static for -mkernel/-fapple-kext. // FIXME: It would be far better to avoid inserting those -static arguments, // but we can't check the deployment target in the translation code until // it is set here. - if (isTargetIPhoneOS() && !isIPhoneOSVersionLT(6, 0)) { + if (isTargetIOSBased() && !isIPhoneOSVersionLT(6, 0) && + getTriple().getArch() != llvm::Triple::arm64 && + getTriple().getArch() != llvm::Triple::aarch64) { for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) { Arg *A = *it; ++it; @@ -854,9 +938,10 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, // Default to use libc++ on OS X 10.9+ and iOS 7+. if (((isTargetMacOS() && !isMacosxVersionLT(10, 9)) || - (isTargetIPhoneOS() && !isIPhoneOSVersionLT(7, 0))) && + (isTargetIOSBased() && !isIPhoneOSVersionLT(7, 0))) && !Args.getLastArg(options::OPT_stdlib_EQ)) - DAL->AddJoinedArg(0, Opts.getOption(options::OPT_stdlib_EQ), "libc++"); + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_stdlib_EQ), + "libc++"); // Validate the C++ standard library choice. CXXStdlibType Type = GetCXXStdlibType(*DAL); @@ -864,8 +949,8 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, // Check whether the target provides libc++. StringRef where; - // Complain about targetting iOS < 5.0 in any way. - if (isTargetIPhoneOS() && isIPhoneOSVersionLT(5, 0)) + // Complain about targeting iOS < 5.0 in any way. + if (isTargetIOSBased() && isIPhoneOSVersionLT(5, 0)) where = "iOS 5.0"; if (where != StringRef()) { @@ -877,11 +962,11 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, return DAL; } -bool Darwin::IsUnwindTablesDefault() const { +bool MachO::IsUnwindTablesDefault() const { return getArch() == llvm::Triple::x86_64; } -bool Darwin::UseDwarfDebugFlags() const { +bool MachO::UseDwarfDebugFlags() const { if (const char *S = ::getenv("RC_DEBUG_OPTIONS")) return S[0] != '\0'; return false; @@ -893,40 +978,145 @@ bool Darwin::UseSjLjExceptions() const { getTriple().getArch() == llvm::Triple::thumb); } -bool Darwin::isPICDefault() const { +bool MachO::isPICDefault() const { return true; } -bool Darwin::isPIEDefault() const { +bool MachO::isPIEDefault() const { return false; } -bool Darwin::isPICDefaultForced() const { - return getArch() == llvm::Triple::x86_64; +bool MachO::isPICDefaultForced() const { + return (getArch() == llvm::Triple::x86_64 || + getArch() == llvm::Triple::arm64 || + getArch() == llvm::Triple::aarch64); } -bool Darwin::SupportsProfiling() const { +bool MachO::SupportsProfiling() const { // Profiling instrumentation is only supported on x86. return getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64; } +void Darwin::addMinVersionArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + VersionTuple TargetVersion = getTargetVersion(); + + // If we had an explicit -mios-simulator-version-min argument, honor that, + // otherwise use the traditional deployment targets. We can't just check the + // is-sim attribute because existing code follows this path, and the linker + // may not handle the argument. + // + // FIXME: We may be able to remove this, once we can verify no one depends on + // it. + if (Args.hasArg(options::OPT_mios_simulator_version_min_EQ)) + CmdArgs.push_back("-ios_simulator_version_min"); + else if (isTargetIOSBased()) + CmdArgs.push_back("-iphoneos_version_min"); + else { + assert(isTargetMacOS() && "unexpected target"); + CmdArgs.push_back("-macosx_version_min"); + } + + CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); +} + +void Darwin::addStartObjectFileArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + // Derived from startfile spec. + if (Args.hasArg(options::OPT_dynamiclib)) { + // Derived from darwin_dylib1 spec. + if (isTargetIOSSimulator()) { + ; // iOS simulator does not need dylib1.o. + } else if (isTargetIPhoneOS()) { + if (isIPhoneOSVersionLT(3, 1)) + CmdArgs.push_back("-ldylib1.o"); + } else { + if (isMacosxVersionLT(10, 5)) + CmdArgs.push_back("-ldylib1.o"); + else if (isMacosxVersionLT(10, 6)) + CmdArgs.push_back("-ldylib1.10.5.o"); + } + } else { + if (Args.hasArg(options::OPT_bundle)) { + if (!Args.hasArg(options::OPT_static)) { + // Derived from darwin_bundle1 spec. + if (isTargetIOSSimulator()) { + ; // iOS simulator does not need bundle1.o. + } else if (isTargetIPhoneOS()) { + if (isIPhoneOSVersionLT(3, 1)) + CmdArgs.push_back("-lbundle1.o"); + } else { + if (isMacosxVersionLT(10, 6)) + CmdArgs.push_back("-lbundle1.o"); + } + } + } else { + if (Args.hasArg(options::OPT_pg) && SupportsProfiling()) { + if (Args.hasArg(options::OPT_static) || + Args.hasArg(options::OPT_object) || + Args.hasArg(options::OPT_preload)) { + CmdArgs.push_back("-lgcrt0.o"); + } else { + CmdArgs.push_back("-lgcrt1.o"); + + // darwin_crt2 spec is empty. + } + // By default on OS X 10.8 and later, we don't link with a crt1.o + // file and the linker knows to use _main as the entry point. But, + // when compiling with -pg, we need to link with the gcrt1.o file, + // so pass the -no_new_main option to tell the linker to use the + // "start" symbol as the entry point. + if (isTargetMacOS() && !isMacosxVersionLT(10, 8)) + CmdArgs.push_back("-no_new_main"); + } else { + if (Args.hasArg(options::OPT_static) || + Args.hasArg(options::OPT_object) || + Args.hasArg(options::OPT_preload)) { + CmdArgs.push_back("-lcrt0.o"); + } else { + // Derived from darwin_crt1 spec. + if (isTargetIOSSimulator()) { + ; // iOS simulator does not need crt1.o. + } else if (isTargetIPhoneOS()) { + if (getArch() == llvm::Triple::arm64 || + getArch() == llvm::Triple::aarch64) + ; // iOS does not need any crt1 files for arm64 + else if (isIPhoneOSVersionLT(3, 1)) + CmdArgs.push_back("-lcrt1.o"); + else if (isIPhoneOSVersionLT(6, 0)) + CmdArgs.push_back("-lcrt1.3.1.o"); + } else { + if (isMacosxVersionLT(10, 5)) + CmdArgs.push_back("-lcrt1.o"); + else if (isMacosxVersionLT(10, 6)) + CmdArgs.push_back("-lcrt1.10.5.o"); + else if (isMacosxVersionLT(10, 8)) + CmdArgs.push_back("-lcrt1.10.6.o"); + + // darwin_crt2 spec is empty. + } + } + } + } + } + + if (!isTargetIPhoneOS() && Args.hasArg(options::OPT_shared_libgcc) && + isMacosxVersionLT(10, 5)) { + const char *Str = Args.MakeArgString(GetFilePath("crt3.o")); + CmdArgs.push_back(Str); + } +} + bool Darwin::SupportsObjCGC() const { - // Garbage collection is supported everywhere except on iPhone OS. - return !isTargetIPhoneOS(); + return isTargetMacOS(); } void Darwin::CheckObjCARC() const { - if (isTargetIPhoneOS() || !isMacosxVersionLT(10, 6)) + if (isTargetIOSBased()|| (isTargetMacOS() && !isMacosxVersionLT(10, 6))) return; getDriver().Diag(diag::err_arc_unsupported_on_toolchain); } -std::string -Darwin_Generic_GCC::ComputeEffectiveClangTriple(const ArgList &Args, - types::ID InputType) const { - return ComputeLLVMTriple(Args, InputType); -} - /// Generic_GCC - A tool chain using the 'gcc' command to perform /// all subcommands; this relies on gcc translating the majority of /// command line options. @@ -1007,7 +1197,7 @@ bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor, return false; } -static StringRef getGCCToolchainDir(const ArgList &Args) { +static llvm::StringRef getGCCToolchainDir(const ArgList &Args) { const Arg *A = Args.getLastArg(options::OPT_gcc_toolchain); if (A) return A->getValue(); @@ -1025,11 +1215,10 @@ static StringRef getGCCToolchainDir(const ArgList &Args) { /// triple. void Generic_GCC::GCCInstallationDetector::init( - const llvm::Triple &TargetTriple, const ArgList &Args) { + const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args) { llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant() : TargetTriple.get32BitArchVariant(); - llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); // The library directories which may contain GCC installations. SmallVector<StringRef, 4> CandidateLibDirs, CandidateBiarchLibDirs; // The compatible GCC triples for this particular architecture. @@ -1075,7 +1264,7 @@ Generic_GCC::GCCInstallationDetector::init( if (!llvm::sys::fs::exists(LibDir)) continue; for (unsigned k = 0, ke = CandidateTripleAliases.size(); k < ke; ++k) - ScanLibDirForGCCTriple(TargetArch, Args, LibDir, + ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, CandidateTripleAliases[k]); } for (unsigned j = 0, je = CandidateBiarchLibDirs.size(); j < je; ++j) { @@ -1084,7 +1273,7 @@ Generic_GCC::GCCInstallationDetector::init( continue; for (unsigned k = 0, ke = CandidateBiarchTripleAliases.size(); k < ke; ++k) - ScanLibDirForGCCTriple(TargetArch, Args, LibDir, + ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, CandidateBiarchTripleAliases[k], /*NeedsBiarchSuffix=*/ true); } @@ -1092,13 +1281,25 @@ Generic_GCC::GCCInstallationDetector::init( } void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { - for (std::set<std::string>::const_iterator - I = CandidateGCCInstallPaths.begin(), - E = CandidateGCCInstallPaths.end(); - I != E; ++I) - OS << "Found candidate GCC installation: " << *I << "\n"; + for (const auto &InstallPath : CandidateGCCInstallPaths) + OS << "Found candidate GCC installation: " << InstallPath << "\n"; + + if (!GCCInstallPath.empty()) + OS << "Selected GCC installation: " << GCCInstallPath << "\n"; + + for (const auto &Multilib : Multilibs) + OS << "Candidate multilib: " << Multilib << "\n"; + + if (Multilibs.size() != 0 || !SelectedMultilib.isDefault()) + OS << "Selected multilib: " << SelectedMultilib << "\n"; +} - OS << "Selected GCC installation: " << GCCInstallPath << "\n"; +bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { + if (BiarchSibling.hasValue()) { + M = BiarchSibling.getValue(); + return true; + } + return false; } /*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples( @@ -1110,43 +1311,62 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { // Declare a bunch of static data sets that we'll select between below. These // are specifically designed to always refer to string literals to avoid any // lifetime or initialization issues. - static const char *const AArch64LibDirs[] = { "/lib" }; + static const char *const AArch64LibDirs[] = { "/lib64", "/lib" }; static const char *const AArch64Triples[] = { "aarch64-none-linux-gnu", - "aarch64-linux-gnu" }; + "aarch64-linux-gnu", + "aarch64-linux-android", + "aarch64-redhat-linux" }; + static const char *const AArch64beLibDirs[] = { "/lib" }; + static const char *const AArch64beTriples[] = { "aarch64_be-none-linux-gnu", + "aarch64_be-linux-gnu" }; static const char *const ARMLibDirs[] = { "/lib" }; static const char *const ARMTriples[] = { "arm-linux-gnueabi", "arm-linux-androideabi" }; static const char *const ARMHFTriples[] = { "arm-linux-gnueabihf", "armv7hl-redhat-linux-gnueabi" }; + static const char *const ARMebLibDirs[] = { "/lib" }; + static const char *const ARMebTriples[] = { "armeb-linux-gnueabi", + "armeb-linux-androideabi" }; + static const char *const ARMebHFTriples[] = { "armeb-linux-gnueabihf", + "armebv7hl-redhat-linux-gnueabi" }; static const char *const X86_64LibDirs[] = { "/lib64", "/lib" }; static const char *const X86_64Triples[] = { "x86_64-linux-gnu", "x86_64-unknown-linux-gnu", "x86_64-pc-linux-gnu", "x86_64-redhat-linux6E", "x86_64-redhat-linux", "x86_64-suse-linux", - "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", "x86_64-slackware-linux" + "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", "x86_64-slackware-linux", + "x86_64-linux-android", "x86_64-unknown-linux" }; + static const char *const X32LibDirs[] = { "/libx32" }; static const char *const X86LibDirs[] = { "/lib32", "/lib" }; static const char *const X86Triples[] = { "i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu", "i386-linux-gnu", "i386-redhat-linux6E", "i686-redhat-linux", "i586-redhat-linux", "i386-redhat-linux", "i586-suse-linux", "i486-slackware-linux", - "i686-montavista-linux" + "i686-montavista-linux", "i686-linux-android", "i586-linux-gnu" }; static const char *const MIPSLibDirs[] = { "/lib" }; static const char *const MIPSTriples[] = { "mips-linux-gnu", - "mips-mti-linux-gnu" }; + "mips-mti-linux-gnu", + "mips-img-linux-gnu" }; static const char *const MIPSELLibDirs[] = { "/lib" }; static const char *const MIPSELTriples[] = { "mipsel-linux-gnu", - "mipsel-linux-android" }; + "mipsel-linux-android", + "mips-img-linux-gnu" }; static const char *const MIPS64LibDirs[] = { "/lib64", "/lib" }; static const char *const MIPS64Triples[] = { "mips64-linux-gnu", - "mips-mti-linux-gnu" }; + "mips-mti-linux-gnu", + "mips-img-linux-gnu", + "mips64-linux-gnuabi64" }; static const char *const MIPS64ELLibDirs[] = { "/lib64", "/lib" }; static const char *const MIPS64ELTriples[] = { "mips64el-linux-gnu", - "mips-mti-linux-gnu" }; + "mips-mti-linux-gnu", + "mips-img-linux-gnu", + "mips64el-linux-android", + "mips64el-linux-gnuabi64" }; static const char *const PPCLibDirs[] = { "/lib32", "/lib" }; static const char *const PPCTriples[] = { @@ -1178,6 +1398,7 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { }; switch (TargetTriple.getArch()) { + case llvm::Triple::arm64: case llvm::Triple::aarch64: LibDirs.append(AArch64LibDirs, AArch64LibDirs + llvm::array_lengthof(AArch64LibDirs)); @@ -1188,6 +1409,17 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { BiarchTripleAliases.append( AArch64Triples, AArch64Triples + llvm::array_lengthof(AArch64Triples)); break; + case llvm::Triple::arm64_be: + case llvm::Triple::aarch64_be: + LibDirs.append(AArch64beLibDirs, + AArch64beLibDirs + llvm::array_lengthof(AArch64beLibDirs)); + TripleAliases.append(AArch64beTriples, + AArch64beTriples + llvm::array_lengthof(AArch64beTriples)); + BiarchLibDirs.append(AArch64beLibDirs, + AArch64beLibDirs + llvm::array_lengthof(AArch64beLibDirs)); + BiarchTripleAliases.append( + AArch64beTriples, AArch64beTriples + llvm::array_lengthof(AArch64beTriples)); + break; case llvm::Triple::arm: case llvm::Triple::thumb: LibDirs.append(ARMLibDirs, ARMLibDirs + llvm::array_lengthof(ARMLibDirs)); @@ -1199,15 +1431,35 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { ARMTriples + llvm::array_lengthof(ARMTriples)); } break; + case llvm::Triple::armeb: + case llvm::Triple::thumbeb: + LibDirs.append(ARMebLibDirs, ARMebLibDirs + llvm::array_lengthof(ARMebLibDirs)); + if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { + TripleAliases.append(ARMebHFTriples, + ARMebHFTriples + llvm::array_lengthof(ARMebHFTriples)); + } else { + TripleAliases.append(ARMebTriples, + ARMebTriples + llvm::array_lengthof(ARMebTriples)); + } + break; case llvm::Triple::x86_64: LibDirs.append(X86_64LibDirs, X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs)); TripleAliases.append(X86_64Triples, X86_64Triples + llvm::array_lengthof(X86_64Triples)); - BiarchLibDirs.append(X86LibDirs, - X86LibDirs + llvm::array_lengthof(X86LibDirs)); - BiarchTripleAliases.append(X86Triples, - X86Triples + llvm::array_lengthof(X86Triples)); + // x32 is always available when x86_64 is available, so adding it as secondary + // arch with x86_64 triples + if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) { + BiarchLibDirs.append(X32LibDirs, + X32LibDirs + llvm::array_lengthof(X32LibDirs)); + BiarchTripleAliases.append(X86_64Triples, + X86_64Triples + llvm::array_lengthof(X86_64Triples)); + } else { + BiarchLibDirs.append(X86LibDirs, + X86LibDirs + llvm::array_lengthof(X86LibDirs)); + BiarchTripleAliases.append(X86Triples, + X86Triples + llvm::array_lengthof(X86Triples)); + } break; case llvm::Triple::x86: LibDirs.append(X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs)); @@ -1332,42 +1584,47 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { BiarchTripleAliases.push_back(BiarchTriple.str()); } -static bool isSoftFloatABI(const ArgList &Args) { - Arg *A = Args.getLastArg(options::OPT_msoft_float, - options::OPT_mhard_float, - options::OPT_mfloat_abi_EQ); - if (!A) return false; +namespace { +// Filter to remove Multilibs that don't exist as a suffix to Path +class FilterNonExistent : public MultilibSet::FilterCallback { + std::string Base; +public: + FilterNonExistent(std::string Base) : Base(Base) {} + bool operator()(const Multilib &M) const override { + return !llvm::sys::fs::exists(Base + M.gccSuffix() + "/crtbegin.o"); + } +}; +} // end anonymous namespace - return A->getOption().matches(options::OPT_msoft_float) || - (A->getOption().matches(options::OPT_mfloat_abi_EQ) && - A->getValue() == StringRef("soft")); +static void addMultilibFlag(bool Enabled, const char *const Flag, + std::vector<std::string> &Flags) { + if (Enabled) + Flags.push_back(std::string("+") + Flag); + else + Flags.push_back(std::string("-") + Flag); } static bool isMipsArch(llvm::Triple::ArchType Arch) { - return Arch == llvm::Triple::mips || - Arch == llvm::Triple::mipsel || - Arch == llvm::Triple::mips64 || - Arch == llvm::Triple::mips64el; + return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel || + Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el; } -static bool isMips16(const ArgList &Args) { - Arg *A = Args.getLastArg(options::OPT_mips16, - options::OPT_mno_mips16); - return A && A->getOption().matches(options::OPT_mips16); +static bool isMips32(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel; } -static bool isMips32r2(const ArgList &Args) { - Arg *A = Args.getLastArg(options::OPT_march_EQ, - options::OPT_mcpu_EQ); - - return A && A->getValue() == StringRef("mips32r2"); +static bool isMips64(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el; } -static bool isMips64r2(const ArgList &Args) { - Arg *A = Args.getLastArg(options::OPT_march_EQ, - options::OPT_mcpu_EQ); +static bool isMipsEL(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::mipsel || Arch == llvm::Triple::mips64el; +} - return A && A->getValue() == StringRef("mips64r2"); +static bool isMips16(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_mips16, + options::OPT_mno_mips16); + return A && A->getOption().matches(options::OPT_mips16); } static bool isMicroMips(const ArgList &Args) { @@ -1376,53 +1633,21 @@ static bool isMicroMips(const ArgList &Args) { return A && A->getOption().matches(options::OPT_mmicromips); } -static bool isMipsFP64(const ArgList &Args) { - Arg *A = Args.getLastArg(options::OPT_mfp64, options::OPT_mfp32); - return A && A->getOption().matches(options::OPT_mfp64); -} - -static bool isMipsNan2008(const ArgList &Args) { - Arg *A = Args.getLastArg(options::OPT_mnan_EQ); - return A && A->getValue() == StringRef("2008"); -} - -// FIXME: There is the same routine in the Tools.cpp. -static bool hasMipsN32ABIArg(const ArgList &Args) { - Arg *A = Args.getLastArg(options::OPT_mabi_EQ); - return A && (A->getValue() == StringRef("n32")); -} - -static bool hasCrtBeginObj(Twine Path) { - return llvm::sys::fs::exists(Path + "/crtbegin.o"); -} +struct DetectedMultilibs { + /// The set of multilibs that the detected installation supports. + MultilibSet Multilibs; -static bool findTargetBiarchSuffix(std::string &Suffix, StringRef Path, - llvm::Triple::ArchType TargetArch, - const ArgList &Args) { - // FIXME: This routine was only intended to model bi-arch toolchains which - // use -m32 and -m64 to swap between variants of a target. It shouldn't be - // doing ABI-based builtin location for MIPS. - if (hasMipsN32ABIArg(Args)) - Suffix = "/n32"; - else if (TargetArch == llvm::Triple::x86_64 || - TargetArch == llvm::Triple::ppc64 || - TargetArch == llvm::Triple::sparcv9 || - TargetArch == llvm::Triple::systemz || - TargetArch == llvm::Triple::mips64 || - TargetArch == llvm::Triple::mips64el) - Suffix = "/64"; - else - Suffix = "/32"; + /// The primary multilib appropriate for the given flags. + Multilib SelectedMultilib; - return hasCrtBeginObj(Path + Suffix); -} - -void Generic_GCC::GCCInstallationDetector::findMIPSABIDirSuffix( - std::string &Suffix, llvm::Triple::ArchType TargetArch, StringRef Path, - const llvm::opt::ArgList &Args) { - if (!isMipsArch(TargetArch)) - return; + /// On Biarch systems, this corresponds to the default multilib when + /// targeting the non-default multilib. Otherwise, it is empty. + llvm::Optional<Multilib> BiarchSibling; +}; +static bool findMIPSMultilibs(const llvm::Triple &TargetTriple, StringRef Path, + const llvm::opt::ArgList &Args, + DetectedMultilibs &Result) { // Some MIPS toolchains put libraries and object files compiled // using different options in to the sub-directoris which names // reflects the flags used for compilation. For example sysroot @@ -1447,71 +1672,362 @@ void Generic_GCC::GCCInstallationDetector::findMIPSABIDirSuffix( // /mips32 // /usr // /lib <= crt*.o files compiled with '-mips32' - // - // Unfortunately different toolchains use different and partially - // overlapped naming schemes. So we have to make a trick for detection - // of using toolchain. We lookup a path which unique for each toolchains. - - bool IsMentorToolChain = hasCrtBeginObj(Path + "/mips16/soft-float"); - bool IsFSFToolChain = hasCrtBeginObj(Path + "/mips32/mips16/sof"); - - if (IsMentorToolChain && IsFSFToolChain) - D.Diag(diag::err_drv_unknown_toolchain); - - if (IsMentorToolChain) { - if (isMips16(Args)) - Suffix += "/mips16"; - else if (isMicroMips(Args)) - Suffix += "/micromips"; - - if (isSoftFloatABI(Args)) - Suffix += "/soft-float"; - - if (TargetArch == llvm::Triple::mipsel || - TargetArch == llvm::Triple::mips64el) - Suffix += "/el"; - } else if (IsFSFToolChain) { - if (TargetArch == llvm::Triple::mips || - TargetArch == llvm::Triple::mipsel) { - if (isMicroMips(Args)) - Suffix += "/micromips"; - else if (isMips32r2(Args)) - Suffix += ""; - else - Suffix += "/mips32"; - if (isMips16(Args)) - Suffix += "/mips16"; - } else { - if (isMips64r2(Args)) - Suffix += hasMipsN32ABIArg(Args) ? "/mips64r2" : "/mips64r2/64"; - else - Suffix += hasMipsN32ABIArg(Args) ? "/mips64" : "/mips64/64"; + FilterNonExistent NonExistent(Path); + + // Check for FSF toolchain multilibs + MultilibSet FSFMipsMultilibs; + { + Multilib MArchMips32 = Multilib() + .gccSuffix("/mips32") + .osSuffix("/mips32") + .includeSuffix("/mips32") + .flag("+m32").flag("-m64").flag("-mmicromips").flag("+march=mips32"); + + Multilib MArchMicroMips = Multilib() + .gccSuffix("/micromips") + .osSuffix("/micromips") + .includeSuffix("/micromips") + .flag("+m32").flag("-m64").flag("+mmicromips"); + + Multilib MArchMips64r2 = Multilib() + .gccSuffix("/mips64r2") + .osSuffix("/mips64r2") + .includeSuffix("/mips64r2") + .flag("-m32").flag("+m64").flag("+march=mips64r2"); + + Multilib MArchMips64 = Multilib() + .gccSuffix("/mips64") + .osSuffix("/mips64") + .includeSuffix("/mips64") + .flag("-m32").flag("+m64").flag("-march=mips64r2"); + + Multilib MArchDefault = Multilib() + .flag("+m32").flag("-m64").flag("-mmicromips").flag("+march=mips32r2"); + + Multilib Mips16 = Multilib() + .gccSuffix("/mips16") + .osSuffix("/mips16") + .includeSuffix("/mips16") + .flag("+mips16"); + + Multilib MAbi64 = Multilib() + .gccSuffix("/64") + .osSuffix("/64") + .includeSuffix("/64") + .flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); + + Multilib BigEndian = Multilib() + .flag("+EB").flag("-EL"); + + Multilib LittleEndian = Multilib() + .gccSuffix("/el") + .osSuffix("/el") + .includeSuffix("/el") + .flag("+EL").flag("-EB"); + + Multilib SoftFloat = Multilib() + .gccSuffix("/sof") + .osSuffix("/sof") + .includeSuffix("/sof") + .flag("+msoft-float"); + + Multilib Nan2008 = Multilib() + .gccSuffix("/nan2008") + .osSuffix("/nan2008") + .includeSuffix("/nan2008") + .flag("+mnan=2008"); + + FSFMipsMultilibs = MultilibSet() + .Either(MArchMips32, MArchMicroMips, + MArchMips64r2, MArchMips64, MArchDefault) + .Maybe(Mips16) + .FilterOut("/mips64/mips16") + .FilterOut("/mips64r2/mips16") + .FilterOut("/micromips/mips16") + .Maybe(MAbi64) + .FilterOut("/micromips/64") + .FilterOut("/mips32/64") + .FilterOut("^/64") + .FilterOut("/mips16/64") + .Either(BigEndian, LittleEndian) + .Maybe(SoftFloat) + .Maybe(Nan2008) + .FilterOut(".*sof/nan2008") + .FilterOut(NonExistent); + } + + // Check for Code Sourcery toolchain multilibs + MultilibSet CSMipsMultilibs; + { + Multilib MArchMips16 = Multilib() + .gccSuffix("/mips16") + .osSuffix("/mips16") + .includeSuffix("/mips16") + .flag("+m32").flag("+mips16"); + + Multilib MArchMicroMips = Multilib() + .gccSuffix("/micromips") + .osSuffix("/micromips") + .includeSuffix("/micromips") + .flag("+m32").flag("+mmicromips"); + + Multilib MArchDefault = Multilib() + .flag("-mips16").flag("-mmicromips"); + + Multilib SoftFloat = Multilib() + .gccSuffix("/soft-float") + .osSuffix("/soft-float") + .includeSuffix("/soft-float") + .flag("+msoft-float"); + + Multilib Nan2008 = Multilib() + .gccSuffix("/nan2008") + .osSuffix("/nan2008") + .includeSuffix("/nan2008") + .flag("+mnan=2008"); + + Multilib DefaultFloat = Multilib() + .flag("-msoft-float").flag("-mnan=2008"); + + Multilib BigEndian = Multilib() + .flag("+EB").flag("-EL"); + + Multilib LittleEndian = Multilib() + .gccSuffix("/el") + .osSuffix("/el") + .includeSuffix("/el") + .flag("+EL").flag("-EB"); + + // Note that this one's osSuffix is "" + Multilib MAbi64 = Multilib() + .gccSuffix("/64") + .includeSuffix("/64") + .flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); + + CSMipsMultilibs = MultilibSet() + .Either(MArchMips16, MArchMicroMips, MArchDefault) + .Either(SoftFloat, Nan2008, DefaultFloat) + .FilterOut("/micromips/nan2008") + .FilterOut("/mips16/nan2008") + .Either(BigEndian, LittleEndian) + .Maybe(MAbi64) + .FilterOut("/mips16.*/64") + .FilterOut("/micromips.*/64") + .FilterOut(NonExistent); + } + + MultilibSet AndroidMipsMultilibs = MultilibSet() + .Maybe(Multilib("/mips-r2").flag("+march=mips32r2")) + .FilterOut(NonExistent); + + MultilibSet DebianMipsMultilibs; + { + Multilib MAbiN32 = Multilib() + .gccSuffix("/n32") + .includeSuffix("/n32") + .flag("+mabi=n32"); + + Multilib M64 = Multilib() + .gccSuffix("/64") + .includeSuffix("/64") + .flag("+m64").flag("-m32").flag("-mabi=n32"); + + Multilib M32 = Multilib() + .flag("-m64").flag("+m32").flag("-mabi=n32"); + + DebianMipsMultilibs = MultilibSet() + .Either(M32, M64, MAbiN32) + .FilterOut(NonExistent); + } + + MultilibSet ImgMultilibs; + { + Multilib Mips64r6 = Multilib() + .gccSuffix("/mips64r6") + .osSuffix("/mips64r6") + .includeSuffix("/mips64r6") + .flag("+m64").flag("-m32"); + + Multilib LittleEndian = Multilib() + .gccSuffix("/el") + .osSuffix("/el") + .includeSuffix("/el") + .flag("+EL").flag("-EB"); + + Multilib MAbi64 = Multilib() + .gccSuffix("/64") + .osSuffix("/64") + .includeSuffix("/64") + .flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); + + ImgMultilibs = MultilibSet() + .Maybe(Mips64r6) + .Maybe(MAbi64) + .Maybe(LittleEndian) + .FilterOut(NonExistent); + } + + StringRef CPUName; + StringRef ABIName; + tools::mips::getMipsCPUAndABI(Args, TargetTriple, CPUName, ABIName); + + llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); + + Multilib::flags_list Flags; + addMultilibFlag(isMips32(TargetArch), "m32", Flags); + addMultilibFlag(isMips64(TargetArch), "m64", Flags); + addMultilibFlag(isMips16(Args), "mips16", Flags); + addMultilibFlag(CPUName == "mips32", "march=mips32", Flags); + addMultilibFlag(CPUName == "mips32r2", "march=mips32r2", Flags); + addMultilibFlag(CPUName == "mips64", "march=mips64", Flags); + addMultilibFlag(CPUName == "mips64r2" || CPUName == "octeon", + "march=mips64r2", Flags); + addMultilibFlag(isMicroMips(Args), "mmicromips", Flags); + addMultilibFlag(tools::mips::isNaN2008(Args, TargetTriple), "mnan=2008", + Flags); + addMultilibFlag(ABIName == "n32", "mabi=n32", Flags); + addMultilibFlag(ABIName == "n64", "mabi=n64", Flags); + addMultilibFlag(isSoftFloatABI(Args), "msoft-float", Flags); + addMultilibFlag(!isSoftFloatABI(Args), "mhard-float", Flags); + addMultilibFlag(isMipsEL(TargetArch), "EL", Flags); + addMultilibFlag(!isMipsEL(TargetArch), "EB", Flags); + + if (TargetTriple.getEnvironment() == llvm::Triple::Android) { + // Select Android toolchain. It's the only choice in that case. + if (AndroidMipsMultilibs.select(Flags, Result.SelectedMultilib)) { + Result.Multilibs = AndroidMipsMultilibs; + return true; + } + return false; + } + + if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies && + TargetTriple.getOS() == llvm::Triple::Linux && + TargetTriple.getEnvironment() == llvm::Triple::GNU) { + // Select mips-img-linux-gnu toolchain. + if (ImgMultilibs.select(Flags, Result.SelectedMultilib)) { + Result.Multilibs = ImgMultilibs; + return true; } + return false; + } - if (TargetArch == llvm::Triple::mipsel || - TargetArch == llvm::Triple::mips64el) - Suffix += "/el"; + // Sort candidates. Toolchain that best meets the directories goes first. + // Then select the first toolchains matches command line flags. + MultilibSet *candidates[] = { &DebianMipsMultilibs, &FSFMipsMultilibs, + &CSMipsMultilibs }; + std::sort( + std::begin(candidates), std::end(candidates), + [](MultilibSet *a, MultilibSet *b) { return a->size() > b->size(); }); + for (const auto &candidate : candidates) { + if (candidate->select(Flags, Result.SelectedMultilib)) { + if (candidate == &DebianMipsMultilibs) + Result.BiarchSibling = Multilib(); + Result.Multilibs = *candidate; + return true; + } + } - if (isSoftFloatABI(Args)) - Suffix += "/sof"; - else { - if (isMipsFP64(Args)) - Suffix += "/fp64"; + { + // Fallback to the regular toolchain-tree structure. + Multilib Default; + Result.Multilibs.push_back(Default); + Result.Multilibs.FilterOut(NonExistent); - if (isMipsNan2008(Args)) - Suffix += "/nan2008"; + if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) { + Result.BiarchSibling = Multilib(); + return true; } } - if (!hasCrtBeginObj(Path + Suffix)) - Suffix.clear(); + return false; +} + +static bool findBiarchMultilibs(const llvm::Triple &TargetTriple, + StringRef Path, const ArgList &Args, + bool NeedsBiarchSuffix, + DetectedMultilibs &Result) { + + // Some versions of SUSE and Fedora on ppc64 put 32-bit libs + // in what would normally be GCCInstallPath and put the 64-bit + // libs in a subdirectory named 64. The simple logic we follow is that + // *if* there is a subdirectory of the right name with crtbegin.o in it, + // we use that. If not, and if not a biarch triple alias, we look for + // crtbegin.o without the subdirectory. + + Multilib Default; + Multilib Alt64 = Multilib() + .gccSuffix("/64") + .includeSuffix("/64") + .flag("-m32").flag("+m64").flag("-mx32"); + Multilib Alt32 = Multilib() + .gccSuffix("/32") + .includeSuffix("/32") + .flag("+m32").flag("-m64").flag("-mx32"); + Multilib Altx32 = Multilib() + .gccSuffix("/x32") + .includeSuffix("/x32") + .flag("-m32").flag("-m64").flag("+mx32"); + + FilterNonExistent NonExistent(Path); + + // Determine default multilib from: 32, 64, x32 + // Also handle cases such as 64 on 32, 32 on 64, etc. + enum { UNKNOWN, WANT32, WANT64, WANTX32 } Want = UNKNOWN; + const bool IsX32 = TargetTriple.getEnvironment() == llvm::Triple::GNUX32; + if (TargetTriple.isArch32Bit() && !NonExistent(Alt32)) + Want = WANT64; + else if (TargetTriple.isArch64Bit() && IsX32 && !NonExistent(Altx32)) + Want = WANT64; + else if (TargetTriple.isArch64Bit() && !IsX32 && !NonExistent(Alt64)) + Want = WANT32; + else { + if (TargetTriple.isArch32Bit()) + Want = NeedsBiarchSuffix ? WANT64 : WANT32; + else if (IsX32) + Want = NeedsBiarchSuffix ? WANT64 : WANTX32; + else + Want = NeedsBiarchSuffix ? WANT32 : WANT64; + } + + if (Want == WANT32) + Default.flag("+m32").flag("-m64").flag("-mx32"); + else if (Want == WANT64) + Default.flag("-m32").flag("+m64").flag("-mx32"); + else if (Want == WANTX32) + Default.flag("-m32").flag("-m64").flag("+mx32"); + else + return false; + + Result.Multilibs.push_back(Default); + Result.Multilibs.push_back(Alt64); + Result.Multilibs.push_back(Alt32); + Result.Multilibs.push_back(Altx32); + + Result.Multilibs.FilterOut(NonExistent); + + Multilib::flags_list Flags; + addMultilibFlag(TargetTriple.isArch64Bit() && !IsX32, "m64", Flags); + addMultilibFlag(TargetTriple.isArch32Bit(), "m32", Flags); + addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "mx32", Flags); + + if (!Result.Multilibs.select(Flags, Result.SelectedMultilib)) + return false; + + if (Result.SelectedMultilib == Alt64 || + Result.SelectedMultilib == Alt32 || + Result.SelectedMultilib == Altx32) + Result.BiarchSibling = Default; + + return true; } void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( - llvm::Triple::ArchType TargetArch, const ArgList &Args, + const llvm::Triple &TargetTriple, const ArgList &Args, const std::string &LibDir, StringRef CandidateTriple, bool NeedsBiarchSuffix) { + llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); // There are various different suffixes involving the triple we // check for. We also record what is necessary to walk from each back // up to the lib directory. @@ -1543,7 +2059,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( (llvm::array_lengthof(LibSuffixes) - (TargetArch != llvm::Triple::x86)); for (unsigned i = 0; i < NumLibSuffixes; ++i) { StringRef LibSuffix = LibSuffixes[i]; - llvm::error_code EC; + std::error_code EC; for (llvm::sys::fs::directory_iterator LI(LibDir + LibSuffix, EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { StringRef VersionText = llvm::sys::path::filename(LI->path()); @@ -1556,28 +2072,21 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( if (CandidateVersion <= Version) continue; - std::string MIPSABIDirSuffix; - findMIPSABIDirSuffix(MIPSABIDirSuffix, TargetArch, LI->path(), Args); - - // Some versions of SUSE and Fedora on ppc64 put 32-bit libs - // in what would normally be GCCInstallPath and put the 64-bit - // libs in a subdirectory named 64. The simple logic we follow is that - // *if* there is a subdirectory of the right name with crtbegin.o in it, - // we use that. If not, and if not a biarch triple alias, we look for - // crtbegin.o without the subdirectory. - - std::string BiarchSuffix; - if (findTargetBiarchSuffix(BiarchSuffix, - LI->path() + MIPSABIDirSuffix, - TargetArch, Args)) { - GCCBiarchSuffix = BiarchSuffix; - } else if (NeedsBiarchSuffix || - !hasCrtBeginObj(LI->path() + MIPSABIDirSuffix)) { + DetectedMultilibs Detected; + + // Debian mips multilibs behave more like the rest of the biarch ones, + // so handle them there + if (isMipsArch(TargetArch)) { + if (!findMIPSMultilibs(TargetTriple, LI->path(), Args, Detected)) + continue; + } else if (!findBiarchMultilibs(TargetTriple, LI->path(), Args, + NeedsBiarchSuffix, Detected)) { continue; - } else { - GCCBiarchSuffix.clear(); } + Multilibs = Detected.Multilibs; + SelectedMultilib = Detected.SelectedMultilib; + BiarchSibling = Detected.BiarchSibling; Version = CandidateVersion; GCCTriple.setTriple(CandidateTriple); // FIXME: We hack together the directory name here instead of @@ -1585,7 +2094,6 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( // Linux. GCCInstallPath = LibDir + LibSuffixes[i] + "/" + VersionText.str(); GCCParentLibPath = GCCInstallPath + InstallSuffixes[i]; - GCCMIPSABIDirSuffix = MIPSABIDirSuffix; IsValid = true; } } @@ -1593,7 +2101,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) - : ToolChain(D, Triple, Args), GCCInstallation(getDriver()) { + : ToolChain(D, Triple, Args), GCCInstallation() { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); @@ -1608,10 +2116,6 @@ Tool *Generic_GCC::getTool(Action::ActionClass AC) const { if (!Preprocess) Preprocess.reset(new tools::gcc::Preprocess(*this)); return Preprocess.get(); - case Action::PrecompileJobClass: - if (!Precompile) - Precompile.reset(new tools::gcc::Precompile(*this)); - return Precompile.get(); case Action::CompileJobClass: if (!Compile) Compile.reset(new tools::gcc::Compile(*this)); @@ -1622,7 +2126,7 @@ Tool *Generic_GCC::getTool(Action::ActionClass AC) const { } Tool *Generic_GCC::buildAssembler() const { - return new tools::gcc::Assemble(*this); + return new tools::gnutools::Assemble(*this); } Tool *Generic_GCC::buildLinker() const { @@ -1650,14 +2154,30 @@ bool Generic_GCC::isPICDefaultForced() const { return false; } -void Generic_GCC::addClangTargetOptions(const ArgList &DriverArgs, +bool Generic_GCC::IsIntegratedAssemblerDefault() const { + return getTriple().getArch() == llvm::Triple::x86 || + getTriple().getArch() == llvm::Triple::x86_64 || + getTriple().getArch() == llvm::Triple::aarch64 || + getTriple().getArch() == llvm::Triple::aarch64_be || + getTriple().getArch() == llvm::Triple::arm64 || + getTriple().getArch() == llvm::Triple::arm64_be || + getTriple().getArch() == llvm::Triple::arm || + getTriple().getArch() == llvm::Triple::armeb || + getTriple().getArch() == llvm::Triple::thumb || + getTriple().getArch() == llvm::Triple::thumbeb; +} + +void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args) const { const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion(); - bool UseInitArrayDefault = + bool UseInitArrayDefault = getTriple().getArch() == llvm::Triple::aarch64 || - (getTriple().getOS() == llvm::Triple::Linux && ( - !V.isOlderThan(4, 7, 0) || - getTriple().getEnvironment() == llvm::Triple::Android)); + getTriple().getArch() == llvm::Triple::aarch64_be || + getTriple().getArch() == llvm::Triple::arm64 || + getTriple().getArch() == llvm::Triple::arm64_be || + (getTriple().getOS() == llvm::Triple::Linux && + (!V.isOlderThan(4, 7, 0) || + getTriple().getEnvironment() == llvm::Triple::Android)); if (DriverArgs.hasFlag(options::OPT_fuse_init_array, options::OPT_fno_use_init_array, @@ -1749,7 +2269,7 @@ Hexagon_TC::Hexagon_TC(const Driver &D, const llvm::Triple &Triple, // Determine version of GCC libraries and headers to use. const std::string HexagonDir(GnuDir + "/lib/gcc/hexagon"); - llvm::error_code ec; + std::error_code ec; GCCVersion MaxVersion= GCCVersion::Parse("0.0.0"); for (llvm::sys::fs::directory_iterator di(HexagonDir, ec), de; !ec && di != de; di = di.increment(ec)) { @@ -1941,6 +2461,21 @@ Tool *Bitrig::buildLinker() const { return new tools::bitrig::Link(*this); } +ToolChain::CXXStdlibType +Bitrig::GetCXXStdlibType(const ArgList &Args) const { + if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { + StringRef Value = A->getValue(); + if (Value == "libstdc++") + return ToolChain::CST_Libstdcxx; + if (Value == "libc++") + return ToolChain::CST_Libcxx; + + getDriver().Diag(diag::err_drv_invalid_stdlib_name) + << A->getAsString(Args); + } + return ToolChain::CST_Libcxx; +} + void Bitrig::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) || @@ -1950,7 +2485,7 @@ void Bitrig::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, switch (GetCXXStdlibType(DriverArgs)) { case ToolChain::CST_Libcxx: addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/"); + getDriver().SysRoot + "/usr/include/c++/v1"); break; case ToolChain::CST_Libstdcxx: addSystemInclude(DriverArgs, CC1Args, @@ -1976,9 +2511,8 @@ void Bitrig::AddCXXStdlibLibArgs(const ArgList &Args, switch (GetCXXStdlibType(Args)) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); - CmdArgs.push_back("-lcxxrt"); - // Include supc++ to provide Unwind until provided by libcxx. - CmdArgs.push_back("-lgcc"); + CmdArgs.push_back("-lc++abi"); + CmdArgs.push_back("-lpthread"); break; case ToolChain::CST_Libstdcxx: CmdArgs.push_back("-lstdc++"); @@ -2060,6 +2594,14 @@ bool FreeBSD::UseSjLjExceptions() const { } } +bool FreeBSD::HasNativeLLVMSupport() const { + return true; +} + +bool FreeBSD::isPIEDefault() const { + return getSanitizerArgs().hasZeroBaseShadow(); +} + /// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly. NetBSD::NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) @@ -2071,8 +2613,39 @@ NetBSD::NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) // doesn't work. // FIXME: It'd be nicer to test if this directory exists, but I'm not sure // what all logic is needed to emulate the '=' prefix here. - if (Triple.getArch() == llvm::Triple::x86) + switch (Triple.getArch()) { + case llvm::Triple::x86: getFilePaths().push_back("=/usr/lib/i386"); + break; + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + switch (Triple.getEnvironment()) { + case llvm::Triple::EABI: + case llvm::Triple::EABIHF: + case llvm::Triple::GNUEABI: + case llvm::Triple::GNUEABIHF: + getFilePaths().push_back("=/usr/lib/eabi"); + break; + default: + getFilePaths().push_back("=/usr/lib/oabi"); + break; + } + break; + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + if (tools::mips::hasMipsAbiArg(Args, "o32")) + getFilePaths().push_back("=/usr/lib/o32"); + else if (tools::mips::hasMipsAbiArg(Args, "64")) + getFilePaths().push_back("=/usr/lib/64"); + break; + case llvm::Triple::sparc: + getFilePaths().push_back("=/usr/lib/sparc"); + break; + default: + break; + } getFilePaths().push_back("=/usr/lib"); } @@ -2101,9 +2674,18 @@ NetBSD::GetCXXStdlibType(const ArgList &Args) const { unsigned Major, Minor, Micro; getTriple().getOSVersion(Major, Minor, Micro); - if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 23) || Major == 0) { - if (getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64) + if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 40) || Major == 0) { + switch (getArch()) { + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::x86: + case llvm::Triple::x86_64: return ToolChain::CST_Libcxx; + default: + break; + } } return ToolChain::CST_Libstdcxx; } @@ -2239,8 +2821,9 @@ static bool IsUbuntu(enum Distro Distro) { } static Distro DetectDistro(llvm::Triple::ArchType Arch) { - OwningPtr<llvm::MemoryBuffer> File; - if (!llvm::MemoryBuffer::getFile("/etc/lsb-release", File)) { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = + llvm::MemoryBuffer::getFile("/etc/lsb-release"); + if (File) { StringRef Data = File.get()->getBuffer(); SmallVector<StringRef, 8> Lines; Data.split(Lines, "\n"); @@ -2265,25 +2848,25 @@ static Distro DetectDistro(llvm::Triple::ArchType Arch) { return Version; } - if (!llvm::MemoryBuffer::getFile("/etc/redhat-release", File)) { + File = llvm::MemoryBuffer::getFile("/etc/redhat-release"); + if (File) { StringRef Data = File.get()->getBuffer(); if (Data.startswith("Fedora release")) return Fedora; - else if (Data.startswith("Red Hat Enterprise Linux") && - Data.find("release 6") != StringRef::npos) - return RHEL6; - else if ((Data.startswith("Red Hat Enterprise Linux") || - Data.startswith("CentOS")) && - Data.find("release 5") != StringRef::npos) - return RHEL5; - else if ((Data.startswith("Red Hat Enterprise Linux") || - Data.startswith("CentOS")) && - Data.find("release 4") != StringRef::npos) - return RHEL4; + if (Data.startswith("Red Hat Enterprise Linux") || + Data.startswith("CentOS")) { + if (Data.find("release 6") != StringRef::npos) + return RHEL6; + else if (Data.find("release 5") != StringRef::npos) + return RHEL5; + else if (Data.find("release 4") != StringRef::npos) + return RHEL4; + } return UnknownDistro; } - if (!llvm::MemoryBuffer::getFile("/etc/debian_version", File)) { + File = llvm::MemoryBuffer::getFile("/etc/debian_version"); + if (File) { StringRef Data = File.get()->getBuffer(); if (Data[0] == '5') return DebianLenny; @@ -2314,7 +2897,7 @@ static Distro DetectDistro(llvm::Triple::ArchType Arch) { /// 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 llvm::Triple TargetTriple, +static std::string getMultiarchTriple(const llvm::Triple &TargetTriple, StringRef SysRoot) { // For most architectures, just use whatever we have rather than trying to be // clever. @@ -2336,18 +2919,36 @@ static std::string getMultiarchTriple(const llvm::Triple TargetTriple, return "arm-linux-gnueabi"; } return TargetTriple.str(); + case llvm::Triple::armeb: + case llvm::Triple::thumbeb: + if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { + if (llvm::sys::fs::exists(SysRoot + "/lib/armeb-linux-gnueabihf")) + return "armeb-linux-gnueabihf"; + } else { + if (llvm::sys::fs::exists(SysRoot + "/lib/armeb-linux-gnueabi")) + return "armeb-linux-gnueabi"; + } + return TargetTriple.str(); case llvm::Triple::x86: if (llvm::sys::fs::exists(SysRoot + "/lib/i386-linux-gnu")) return "i386-linux-gnu"; return TargetTriple.str(); case llvm::Triple::x86_64: - if (llvm::sys::fs::exists(SysRoot + "/lib/x86_64-linux-gnu")) + // We don't want this for x32, otherwise it will match x86_64 libs + if (TargetTriple.getEnvironment() != llvm::Triple::GNUX32 && + llvm::sys::fs::exists(SysRoot + "/lib/x86_64-linux-gnu")) return "x86_64-linux-gnu"; return TargetTriple.str(); + case llvm::Triple::arm64: case llvm::Triple::aarch64: if (llvm::sys::fs::exists(SysRoot + "/lib/aarch64-linux-gnu")) return "aarch64-linux-gnu"; return TargetTriple.str(); + case llvm::Triple::arm64_be: + case llvm::Triple::aarch64_be: + if (llvm::sys::fs::exists(SysRoot + "/lib/aarch64_be-linux-gnu")) + return "aarch64_be-linux-gnu"; + return TargetTriple.str(); case llvm::Triple::mips: if (llvm::sys::fs::exists(SysRoot + "/lib/mips-linux-gnu")) return "mips-linux-gnu"; @@ -2356,6 +2957,18 @@ static std::string getMultiarchTriple(const llvm::Triple TargetTriple, if (llvm::sys::fs::exists(SysRoot + "/lib/mipsel-linux-gnu")) return "mipsel-linux-gnu"; return TargetTriple.str(); + case llvm::Triple::mips64: + if (llvm::sys::fs::exists(SysRoot + "/lib/mips64-linux-gnu")) + return "mips64-linux-gnu"; + if (llvm::sys::fs::exists(SysRoot + "/lib/mips64-linux-gnuabi64")) + return "mips64-linux-gnuabi64"; + return TargetTriple.str(); + case llvm::Triple::mips64el: + if (llvm::sys::fs::exists(SysRoot + "/lib/mips64el-linux-gnu")) + return "mips64el-linux-gnu"; + if (llvm::sys::fs::exists(SysRoot + "/lib/mips64el-linux-gnuabi64")) + return "mips64el-linux-gnuabi64"; + return TargetTriple.str(); case llvm::Triple::ppc: if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnuspe")) return "powerpc-linux-gnuspe"; @@ -2376,36 +2989,40 @@ static void addPathIfExists(Twine Path, ToolChain::path_list &Paths) { if (llvm::sys::fs::exists(Path)) Paths.push_back(Path.str()); } -static StringRef getMultilibDir(const llvm::Triple &Triple, - const ArgList &Args) { +static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { if (isMipsArch(Triple.getArch())) { // lib32 directory has a special meaning on MIPS targets. // It contains N32 ABI binaries. Use this folder if produce // code for N32 ABI only. - if (hasMipsN32ABIArg(Args)) + if (tools::mips::hasMipsAbiArg(Args, "n32")) return "lib32"; return Triple.isArch32Bit() ? "lib" : "lib64"; } - // It happens that only x86 and PPC use the 'lib32' variant of multilib, and + // 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' multilib search path being considered. So we only enable + // 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 multilib spellings with the lib dir spellings in the + // 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 || Triple.getArch() == llvm::Triple::ppc) return "lib32"; + if (Triple.getArch() == llvm::Triple::x86_64 && + Triple.getEnvironment() == llvm::Triple::GNUX32) + return "libx32"; + return Triple.isArch32Bit() ? "lib" : "lib64"; } Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args); + GCCInstallation.init(D, Triple, Args); + Multilibs = GCCInstallation.getMultilibs(); llvm::Triple::ArchType Arch = Triple.getArch(); std::string SysRoot = computeSysRoot(); @@ -2421,7 +3038,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + GCCInstallation.getTriple().str() + "/bin").str()); - Linker = GetProgramPath("ld"); + Linker = GetLinkerPath(); Distro Distro = DetectDistro(Arch); @@ -2473,29 +3090,20 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // to the link paths. path_list &Paths = getFilePaths(); - const std::string Multilib = getMultilibDir(Triple, Args); + const std::string OSLibDir = getOSLibDir(Triple, Args); const std::string MultiarchTriple = getMultiarchTriple(Triple, SysRoot); // Add the multilib suffixed paths where they are available. if (GCCInstallation.isValid()) { const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); const std::string &LibPath = GCCInstallation.getParentLibPath(); + const Multilib &Multilib = GCCInstallation.getMultilib(); // Sourcery CodeBench MIPS toolchain holds some libraries under // a biarch-like suffix of the GCC installation. - // - // FIXME: It would be cleaner to model this as a variant of bi-arch. IE, - // instead of a '64' biarch suffix it would be 'el' or something. - if (IsAndroid && IsMips && isMips32r2(Args)) { - assert(GCCInstallation.getBiarchSuffix().empty() && - "Unexpected bi-arch suffix"); - addPathIfExists(GCCInstallation.getInstallPath() + "/mips-r2", Paths); - } else { - addPathIfExists((GCCInstallation.getInstallPath() + - GCCInstallation.getMIPSABIDirSuffix() + - GCCInstallation.getBiarchSuffix()), - Paths); - } + addPathIfExists((GCCInstallation.getInstallPath() + + Multilib.gccSuffix()), + Paths); // GCC cross compiling toolchains will install target libraries which ship // as part of the toolchain under <prefix>/<triple>/<libdir> rather than as @@ -2503,7 +3111,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // <prefix>/<libdir>/gcc/<triple>/<version>. This decision is somewhat // debatable, but is the reality today. We need to search this tree even // when we have a sysroot somewhere else. It is the responsibility of - // whomever is doing the cross build targetting a sysroot using a GCC + // whomever is doing the cross build targeting a sysroot using a GCC // installation that is *not* within the system root to ensure two things: // // 1) Any DSOs that are linked in from this tree or from the install path @@ -2515,8 +3123,8 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // // Note that this matches the GCC behavior. See the below comment for where // Clang diverges from GCC's behavior. - addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + Multilib + - GCCInstallation.getMIPSABIDirSuffix(), + addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + OSLibDir + + Multilib.osSuffix(), Paths); // If the GCC installation we found is inside of the sysroot, we want to @@ -2530,45 +3138,64 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // a bug. if (StringRef(LibPath).startswith(SysRoot)) { addPathIfExists(LibPath + "/" + MultiarchTriple, Paths); - addPathIfExists(LibPath + "/../" + Multilib, Paths); + addPathIfExists(LibPath + "/../" + OSLibDir, Paths); } } + + // Similar to the logic for GCC above, if we 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.Dir + "/../lib/" + MultiarchTriple, Paths); + addPathIfExists(D.Dir + "/../" + OSLibDir, Paths); + } + addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths); - addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths); + addPathIfExists(SysRoot + "/lib/../" + OSLibDir, Paths); addPathIfExists(SysRoot + "/usr/lib/" + MultiarchTriple, Paths); - addPathIfExists(SysRoot + "/usr/lib/../" + Multilib, Paths); + addPathIfExists(SysRoot + "/usr/lib/../" + OSLibDir, Paths); // Try walking via the GCC triple path in case of biarch or multiarch GCC // installations with strange symlinks. if (GCCInstallation.isValid()) { addPathIfExists(SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() + - "/../../" + Multilib, Paths); + "/../../" + OSLibDir, Paths); - // Add the non-multilib suffixed paths (if potentially different). - const std::string &LibPath = GCCInstallation.getParentLibPath(); - const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); - if (!GCCInstallation.getBiarchSuffix().empty()) + // Add the 'other' biarch variant path + Multilib BiarchSibling; + if (GCCInstallation.getBiarchSibling(BiarchSibling)) { addPathIfExists(GCCInstallation.getInstallPath() + - GCCInstallation.getMIPSABIDirSuffix(), Paths); + BiarchSibling.gccSuffix(), Paths); + } // See comments above on the multilib variant for details of why this is // included even from outside the sysroot. + const std::string &LibPath = GCCInstallation.getParentLibPath(); + const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); + const Multilib &Multilib = GCCInstallation.getMultilib(); addPathIfExists(LibPath + "/../" + GCCTriple.str() + - "/lib" + GCCInstallation.getMIPSABIDirSuffix(), Paths); + "/lib" + Multilib.osSuffix(), Paths); // See comments above on the multilib variant for details of why this is // only included from within the sysroot. if (StringRef(LibPath).startswith(SysRoot)) addPathIfExists(LibPath, Paths); } + + // Similar to the logic for GCC above, 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.Dir + "/../lib", Paths); + addPathIfExists(SysRoot + "/lib", Paths); addPathIfExists(SysRoot + "/usr/lib", Paths); } -bool FreeBSD::HasNativeLLVMSupport() const { - return true; -} - bool Linux::HasNativeLLVMSupport() const { return true; } @@ -2594,15 +3221,15 @@ std::string Linux::computeSysRoot() const { const StringRef InstallDir = GCCInstallation.getInstallPath(); const StringRef TripleStr = GCCInstallation.getTriple().str(); - const StringRef MIPSABIDirSuffix = GCCInstallation.getMIPSABIDirSuffix(); + const Multilib &Multilib = GCCInstallation.getMultilib(); std::string Path = (InstallDir + "/../../../../" + TripleStr + "/libc" + - MIPSABIDirSuffix).str(); + Multilib.osSuffix()).str(); if (llvm::sys::fs::exists(Path)) return Path; - Path = (InstallDir + "/../../../../sysroot" + MIPSABIDirSuffix).str(); + Path = (InstallDir + "/../../../../sysroot" + Multilib.osSuffix()).str(); if (llvm::sys::fs::exists(Path)) return Path; @@ -2635,10 +3262,9 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, if (CIncludeDirs != "") { SmallVector<StringRef, 5> dirs; CIncludeDirs.split(dirs, ":"); - for (SmallVectorImpl<StringRef>::iterator I = dirs.begin(), E = dirs.end(); - I != E; ++I) { - StringRef Prefix = llvm::sys::path::is_absolute(*I) ? SysRoot : ""; - addExternCSystemInclude(DriverArgs, CC1Args, Prefix + *I); + for (StringRef dir : dirs) { + StringRef Prefix = llvm::sys::path::is_absolute(dir) ? SysRoot : ""; + addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); } return; } @@ -2695,18 +3321,32 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, const StringRef MIPSELMultiarchIncludeDirs[] = { "/usr/include/mipsel-linux-gnu" }; + const StringRef MIPS64MultiarchIncludeDirs[] = { + "/usr/include/mips64-linux-gnu", + "/usr/include/mips64-linux-gnuabi64" + }; + const StringRef MIPS64ELMultiarchIncludeDirs[] = { + "/usr/include/mips64el-linux-gnu", + "/usr/include/mips64el-linux-gnuabi64" + }; const StringRef PPCMultiarchIncludeDirs[] = { "/usr/include/powerpc-linux-gnu" }; const StringRef PPC64MultiarchIncludeDirs[] = { "/usr/include/powerpc64-linux-gnu" }; + const StringRef PPC64LEMultiarchIncludeDirs[] = { + "/usr/include/powerpc64le-linux-gnu" + }; ArrayRef<StringRef> MultiarchIncludeDirs; if (getTriple().getArch() == llvm::Triple::x86_64) { MultiarchIncludeDirs = X86_64MultiarchIncludeDirs; } else if (getTriple().getArch() == llvm::Triple::x86) { MultiarchIncludeDirs = X86MultiarchIncludeDirs; - } else if (getTriple().getArch() == llvm::Triple::aarch64) { + } else if (getTriple().getArch() == llvm::Triple::aarch64 || + getTriple().getArch() == llvm::Triple::aarch64_be || + getTriple().getArch() == llvm::Triple::arm64 || + getTriple().getArch() == llvm::Triple::arm64_be) { MultiarchIncludeDirs = AArch64MultiarchIncludeDirs; } else if (getTriple().getArch() == llvm::Triple::arm) { if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF) @@ -2717,16 +3357,20 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, MultiarchIncludeDirs = MIPSMultiarchIncludeDirs; } else if (getTriple().getArch() == llvm::Triple::mipsel) { MultiarchIncludeDirs = MIPSELMultiarchIncludeDirs; + } else if (getTriple().getArch() == llvm::Triple::mips64) { + MultiarchIncludeDirs = MIPS64MultiarchIncludeDirs; + } else if (getTriple().getArch() == llvm::Triple::mips64el) { + MultiarchIncludeDirs = MIPS64ELMultiarchIncludeDirs; } else if (getTriple().getArch() == llvm::Triple::ppc) { MultiarchIncludeDirs = PPCMultiarchIncludeDirs; } else if (getTriple().getArch() == llvm::Triple::ppc64) { MultiarchIncludeDirs = PPC64MultiarchIncludeDirs; + } else if (getTriple().getArch() == llvm::Triple::ppc64le) { + MultiarchIncludeDirs = PPC64LEMultiarchIncludeDirs; } - for (ArrayRef<StringRef>::iterator I = MultiarchIncludeDirs.begin(), - E = MultiarchIncludeDirs.end(); - I != E; ++I) { - if (llvm::sys::fs::exists(SysRoot + *I)) { - addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + *I); + for (StringRef Dir : MultiarchIncludeDirs) { + if (llvm::sys::fs::exists(SysRoot + Dir)) { + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + Dir); break; } } @@ -2742,33 +3386,39 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); } -/// \brief Helper to add the three variant paths for a libstdc++ installation. -/*static*/ bool Linux::addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir, - const ArgList &DriverArgs, - ArgStringList &CC1Args) { - if (!llvm::sys::fs::exists(Base)) - return false; - addSystemInclude(DriverArgs, CC1Args, Base); - addSystemInclude(DriverArgs, CC1Args, Base + "/" + TargetArchDir); - addSystemInclude(DriverArgs, CC1Args, Base + "/backward"); - return true; -} - -/// \brief Helper to add an extra variant path for an (Ubuntu) multilib -/// libstdc++ installation. +/// \brief Helper to add the variant paths of a libstdc++ installation. /*static*/ bool Linux::addLibStdCXXIncludePaths(Twine Base, Twine Suffix, - Twine TargetArchDir, - Twine BiarchSuffix, - Twine MIPSABIDirSuffix, + StringRef GCCTriple, + StringRef GCCMultiarchTriple, + StringRef TargetMultiarchTriple, + Twine IncludeSuffix, const ArgList &DriverArgs, ArgStringList &CC1Args) { - if (!addLibStdCXXIncludePaths(Base + Suffix, - TargetArchDir + MIPSABIDirSuffix + BiarchSuffix, - DriverArgs, CC1Args)) + if (!llvm::sys::fs::exists(Base + Suffix)) return false; - addSystemInclude(DriverArgs, CC1Args, Base + "/" + TargetArchDir + Suffix - + MIPSABIDirSuffix + BiarchSuffix); + addSystemInclude(DriverArgs, CC1Args, Base + Suffix); + + // The vanilla GCC layout of libstdc++ headers uses a triple subdirectory. If + // that path exists or we have neither a GCC nor target multiarch triple, use + // this vanilla search path. + if ((GCCMultiarchTriple.empty() && TargetMultiarchTriple.empty()) || + llvm::sys::fs::exists(Base + Suffix + "/" + GCCTriple + IncludeSuffix)) { + addSystemInclude(DriverArgs, CC1Args, + Base + Suffix + "/" + GCCTriple + IncludeSuffix); + } else { + // Otherwise try to use multiarch naming schemes which have normalized the + // triples and put the triple before the suffix. + // + // GCC surprisingly uses *both* the GCC triple with a multilib suffix and + // the target triple, so we support that here. + addSystemInclude(DriverArgs, CC1Args, + Base + "/" + GCCMultiarchTriple + Suffix + IncludeSuffix); + addSystemInclude(DriverArgs, CC1Args, + Base + "/" + TargetMultiarchTriple + Suffix); + } + + addSystemInclude(DriverArgs, CC1Args, Base + Suffix + "/backward"); return true; } @@ -2780,9 +3430,23 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, // Check if libc++ has been enabled and provide its include paths if so. if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) { - // libc++ is always installed at a fixed path on Linux currently. - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/v1"); + const std::string LibCXXIncludePathCandidates[] = { + // The primary location is within the Clang installation. + // FIXME: We shouldn't hard code 'v1' here to make Clang future proof to + // newer ABI versions. + getDriver().Dir + "/../include/c++/v1", + + // We also check the system as for a long time this is the only place Clang looked. + // FIXME: We should really remove this. It doesn't make any sense. + getDriver().SysRoot + "/usr/include/c++/v1" + }; + for (const auto &IncludePath : LibCXXIncludePathCandidates) { + if (!llvm::sys::fs::exists(IncludePath)) + continue; + // Add the first candidate that exists. + addSystemInclude(DriverArgs, CC1Args, IncludePath); + break; + } return; } @@ -2797,16 +3461,23 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, StringRef LibDir = GCCInstallation.getParentLibPath(); StringRef InstallDir = GCCInstallation.getInstallPath(); StringRef TripleStr = GCCInstallation.getTriple().str(); - StringRef MIPSABIDirSuffix = GCCInstallation.getMIPSABIDirSuffix(); - StringRef BiarchSuffix = GCCInstallation.getBiarchSuffix(); + const Multilib &Multilib = GCCInstallation.getMultilib(); + const std::string GCCMultiarchTriple = + getMultiarchTriple(GCCInstallation.getTriple(), getDriver().SysRoot); + const std::string TargetMultiarchTriple = + getMultiarchTriple(getTriple(), getDriver().SysRoot); const GCCVersion &Version = GCCInstallation.getVersion(); + // The primary search for libstdc++ supports multiarch variants. if (addLibStdCXXIncludePaths(LibDir.str() + "/../include", - "/c++/" + Version.Text, TripleStr, BiarchSuffix, - MIPSABIDirSuffix, DriverArgs, CC1Args)) + "/c++/" + Version.Text, TripleStr, GCCMultiarchTriple, + TargetMultiarchTriple, + Multilib.includeSuffix(), DriverArgs, CC1Args)) return; - const std::string IncludePathCandidates[] = { + // Otherwise, fall back on a bunch of options which don't use multiarch + // layouts for simplicity. + const std::string LibStdCXXIncludePathCandidates[] = { // Gentoo is weird and places its headers inside the GCC install, so if the // first attempt to find the headers fails, try these patterns. InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." + @@ -2819,10 +3490,11 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, LibDir.str() + "/../include/c++", }; - for (unsigned i = 0; i < llvm::array_lengthof(IncludePathCandidates); ++i) { - if (addLibStdCXXIncludePaths(IncludePathCandidates[i], - TripleStr + MIPSABIDirSuffix + BiarchSuffix, - DriverArgs, CC1Args)) + for (const auto &IncludePath : LibStdCXXIncludePathCandidates) { + if (addLibStdCXXIncludePaths(IncludePath, /*Suffix*/ "", TripleStr, + /*GCCMultiarchTriple*/ "", + /*TargetMultiarchTriple*/ "", + Multilib.includeSuffix(), DriverArgs, CC1Args)) break; } } @@ -2892,7 +3564,6 @@ bool XCore::hasBlocksRuntime() const { return false; } - void XCore::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdinc) || |