diff options
Diffstat (limited to 'lib/Driver/ToolChains.cpp')
-rw-r--r-- | lib/Driver/ToolChains.cpp | 780 |
1 files changed, 347 insertions, 433 deletions
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 035af21975..fffba0e4e5 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -42,8 +42,8 @@ using namespace clang; /// Darwin - Darwin tool chain for i386 and x86_64. -Darwin::Darwin(const Driver &D, const llvm::Triple& Triple) - : ToolChain(D, Triple), TargetInitialized(false) +Darwin::Darwin(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) + : ToolChain(D, Triple, Args), TargetInitialized(false) { // Compute the initial Darwin version from the triple unsigned Major, Minor, Micro; @@ -151,10 +151,6 @@ StringRef Darwin::getDarwinArchName(const ArgList &Args) const { } Darwin::~Darwin() { - // Free tool implementations. - for (llvm::DenseMap<unsigned, Tool*>::iterator - it = Tools.begin(), ie = Tools.end(); it != ie; ++it) - delete it->second; } std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, @@ -176,55 +172,36 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, void Generic_ELF::anchor() {} -Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key = JA.getKind(); - - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) { - // FIXME: This seems like a hacky way to choose clang frontend. - Key = Action::AnalyzeJobClass; - } - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::InputClass: - case Action::BindArchClass: - llvm_unreachable("Invalid tool kind."); - case Action::PreprocessJobClass: - case Action::AnalyzeJobClass: - case Action::MigrateJobClass: - case Action::PrecompileJobClass: - case Action::CompileJobClass: - T = new tools::Clang(*this); break; - case Action::AssembleJobClass: { - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::darwin::Assemble(*this); - break; - } - case Action::LinkJobClass: - T = new tools::darwin::Link(*this); break; - case Action::LipoJobClass: - T = new tools::darwin::Lipo(*this); break; - case Action::DsymutilJobClass: - T = new tools::darwin::Dsymutil(*this); break; - case Action::VerifyJobClass: - T = new tools::darwin::VerifyDebug(*this); break; - } +Tool *Darwin::getTool(Action::ActionClass AC) const { + switch (AC) { + case Action::LipoJobClass: + if (!Lipo) + Lipo.reset(new tools::darwin::Lipo(*this)); + return Lipo.get(); + case Action::DsymutilJobClass: + if (!Dsymutil) + Dsymutil.reset(new tools::darwin::Dsymutil(*this)); + return Dsymutil.get(); + case Action::VerifyJobClass: + if (!VerifyDebug) + VerifyDebug.reset(new tools::darwin::VerifyDebug(*this)); + return VerifyDebug.get(); + default: + return ToolChain::getTool(AC); } +} - return *T; +Tool *Darwin::buildLinker() const { + return new tools::darwin::Link(*this); } +Tool *Darwin::buildAssembler() const { + return new tools::darwin::Assemble(*this); +} -DarwinClang::DarwinClang(const Driver &D, const llvm::Triple& Triple) - : Darwin(D, Triple) +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) @@ -317,7 +294,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, } } - SanitizerArgs Sanitize(getDriver(), Args); + SanitizerArgs Sanitize(*this, Args); // Add Ubsan runtime library, if required. if (Sanitize.needsUbsanRt()) { @@ -335,17 +312,19 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, // Add ASAN runtime library, if required. Dynamic libraries and bundles // should not be linked with the runtime library. if (Sanitize.needsAsanRt()) { - if (Args.hasArg(options::OPT_dynamiclib) || - Args.hasArg(options::OPT_bundle)) { - // Assume the binary will provide the ASan runtime. - } else if (isTargetIPhoneOS()) { + if (isTargetIPhoneOS() && !isTargetIOSSimulator()) { getDriver().Diag(diag::err_drv_clang_unsupported_per_platform) << "-fsanitize=address"; } else { - AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.asan_osx_dynamic.dylib", true); - - // The ASAN runtime library requires C++. - AddCXXStdlibLibArgs(Args, CmdArgs); + if (Args.hasArg(options::OPT_dynamiclib) || + Args.hasArg(options::OPT_bundle)) { + // Assume the binary will provide the ASan runtime. + } else { + AddLinkRuntimeLib(Args, CmdArgs, + "libclang_rt.asan_osx_dynamic.dylib", true); + // The ASAN runtime library requires C++. + AddCXXStdlibLibArgs(Args, CmdArgs); + } } } @@ -899,6 +878,10 @@ bool Darwin::isPICDefault() const { return true; } +bool Darwin::isPIEDefault() const { + return false; +} + bool Darwin::isPICDefaultForced() const { return getArch() == llvm::Triple::x86_64; } @@ -1103,6 +1086,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( }; static const char *const ARMHFTriples[] = { "arm-linux-gnueabihf", + "armv7hl-redhat-linux-gnueabi" }; static const char *const X86_64LibDirs[] = { "/lib64", "/lib" }; @@ -1137,7 +1121,8 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( static const char *const MIPSELLibDirs[] = { "/lib" }; static const char *const MIPSELTriples[] = { "mipsel-linux-gnu", - "mipsel-linux-android" + "mipsel-linux-android", + "mips-linux-gnu" }; static const char *const MIPS64LibDirs[] = { "/lib64", "/lib" }; @@ -1149,6 +1134,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( static const char *const PPCTriples[] = { "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", + "powerpc-linux-gnuspe", "powerpc-suse-linux", "powerpc-montavista-linuxspe" }; @@ -1160,6 +1146,15 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( "ppc64-redhat-linux" }; + static const char *const SystemZLibDirs[] = { "/lib64", "/lib" }; + static const char *const SystemZTriples[] = { + "s390x-linux-gnu", + "s390x-unknown-linux-gnu", + "s390x-ibm-linux-gnu", + "s390x-suse-linux", + "s390x-redhat-linux" + }; + switch (TargetTriple.getArch()) { case llvm::Triple::aarch64: LibDirs.append(AArch64LibDirs, AArch64LibDirs @@ -1260,6 +1255,12 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( MultiarchTripleAliases.append( PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples)); break; + case llvm::Triple::systemz: + LibDirs.append( + SystemZLibDirs, SystemZLibDirs + llvm::array_lengthof(SystemZLibDirs)); + TripleAliases.append( + SystemZTriples, SystemZTriples + llvm::array_lengthof(SystemZTriples)); + break; default: // By default, just rely on the standard lib directories and the original @@ -1276,29 +1277,102 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( MultiarchTripleAliases.push_back(MultiarchTriple.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; + + return A->getOption().matches(options::OPT_msoft_float) || + (A->getOption().matches(options::OPT_mfloat_abi_EQ) && + A->getValue() == StringRef("soft")); +} + +static bool isMipsArch(llvm::Triple::ArchType Arch) { + 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 isMicroMips(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_mmicromips, + options::OPT_mno_micromips); + return A && A->getOption().matches(options::OPT_mmicromips); +} + // 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 StringRef getTargetMultiarchSuffix(llvm::Triple::ArchType TargetArch, - const ArgList &Args) { - if (TargetArch == llvm::Triple::x86_64 || - TargetArch == llvm::Triple::ppc64) - return "/64"; +static void appendMipsTargetSuffix(std::string &Path, + llvm::Triple::ArchType TargetArch, + const ArgList &Args) { + if (isMips16(Args)) + Path += "/mips16"; + else if (isMicroMips(Args)) + Path += "/micromips"; + + if (isSoftFloatABI(Args)) + Path += "/soft-float"; + if (TargetArch == llvm::Triple::mipsel || + TargetArch == llvm::Triple::mips64el) + Path += "/el"; +} + +static StringRef getMipsTargetABISuffix(llvm::Triple::ArchType TargetArch, + const ArgList &Args) { if (TargetArch == llvm::Triple::mips64 || - TargetArch == llvm::Triple::mips64el) { - if (hasMipsN32ABIArg(Args)) - return "/n32"; - else - return "/64"; - } + TargetArch == llvm::Triple::mips64el) + return hasMipsN32ABIArg(Args) ? "/n32" : "/64"; return "/32"; } +static bool findTargetMultiarchSuffix(std::string &Suffix, + StringRef Path, + llvm::Triple::ArchType TargetArch, + const ArgList &Args) { + if (isMipsArch(TargetArch)) { + StringRef ABISuffix = getMipsTargetABISuffix(TargetArch, Args); + + // First build and check a complex path to crtbegin.o + // depends on command line options (-mips16, -msoft-float, ...) + // like mips-linux-gnu/4.7/mips16/soft-float/el/crtbegin.o + appendMipsTargetSuffix(Suffix, TargetArch, Args); + + if (TargetArch == llvm::Triple::mips64 || + TargetArch == llvm::Triple::mips64el) + Suffix += ABISuffix; + + if (llvm::sys::fs::exists(Path + Suffix + "/crtbegin.o")) + return true; + + // Then fall back and probe a simple case like + // mips-linux-gnu/4.7/32/crtbegin.o + Suffix = ABISuffix; + return llvm::sys::fs::exists(Path + Suffix + "/crtbegin.o"); + } + + if (TargetArch == llvm::Triple::x86_64 || + TargetArch == llvm::Triple::ppc64 || + TargetArch == llvm::Triple::systemz) + Suffix = "/64"; + else + Suffix = "/32"; + + return llvm::sys::fs::exists(Path + Suffix + "/crtbegin.o"); +} + void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( llvm::Triple::ArchType TargetArch, const ArgList &Args, const std::string &LibDir, @@ -1348,9 +1422,11 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( // *if* there is a subdirectory of the right name with crtbegin.o in it, // we use that. If not, and if not a multiarch triple, we look for // crtbegin.o without the subdirectory. - StringRef MultiarchSuffix = getTargetMultiarchSuffix(TargetArch, Args); - if (llvm::sys::fs::exists(LI->path() + MultiarchSuffix + "/crtbegin.o")) { - GCCMultiarchSuffix = MultiarchSuffix.str(); + + std::string MultiarchSuffix; + if (findTargetMultiarchSuffix(MultiarchSuffix, + LI->path(), TargetArch, Args)) { + GCCMultiarchSuffix = MultiarchSuffix; } else { if (NeedsMultiarchSuffix || !llvm::sys::fs::exists(LI->path() + "/crtbegin.o")) @@ -1372,60 +1448,40 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) - : ToolChain(D, Triple), GCCInstallation(getDriver(), Triple, Args) { + : ToolChain(D, Triple, Args), GCCInstallation(getDriver(), Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); } Generic_GCC::~Generic_GCC() { - // Free tool implementations. - for (llvm::DenseMap<unsigned, Tool*>::iterator - it = Tools.begin(), ie = Tools.end(); it != ie; ++it) - delete it->second; -} - -Tool &Generic_GCC::SelectTool(const Compilation &C, - const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::InputClass: - case Action::BindArchClass: - llvm_unreachable("Invalid tool kind."); - case Action::PreprocessJobClass: - T = new tools::gcc::Preprocess(*this); break; - case Action::PrecompileJobClass: - T = new tools::gcc::Precompile(*this); break; - case Action::AnalyzeJobClass: - case Action::MigrateJobClass: - T = new tools::Clang(*this); break; - case Action::CompileJobClass: - T = new tools::gcc::Compile(*this); break; - case Action::AssembleJobClass: - T = new tools::gcc::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::gcc::Link(*this); break; - - // This is a bit ungeneric, but the only platform using a driver - // driver is Darwin. - case Action::LipoJobClass: - T = new tools::darwin::Lipo(*this); break; - case Action::DsymutilJobClass: - T = new tools::darwin::Dsymutil(*this); break; - case Action::VerifyJobClass: - T = new tools::darwin::VerifyDebug(*this); break; - } +} + +Tool *Generic_GCC::getTool(Action::ActionClass AC) const { + switch (AC) { + case Action::PreprocessJobClass: + 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)); + return Compile.get(); + default: + return ToolChain::getTool(AC); } +} - return *T; +Tool *Generic_GCC::buildAssembler() const { + return new tools::gcc::Assemble(*this); +} + +Tool *Generic_GCC::buildLinker() const { + return new tools::gcc::Link(*this); } bool Generic_GCC::IsUnwindTablesDefault() const { @@ -1436,6 +1492,10 @@ bool Generic_GCC::isPICDefault() const { return false; } +bool Generic_GCC::isPIEDefault() const { + return false; +} + bool Generic_GCC::isPICDefaultForced() const { return false; } @@ -1550,47 +1610,14 @@ Hexagon_TC::Hexagon_TC(const Driver &D, const llvm::Triple &Triple, } Hexagon_TC::~Hexagon_TC() { - // Free tool implementations. - for (llvm::DenseMap<unsigned, Tool*>::iterator - it = Tools.begin(), ie = Tools.end(); it != ie; ++it) - delete it->second; -} - -Tool &Hexagon_TC::SelectTool(const Compilation &C, - const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - // if (JA.getKind () == Action::CompileJobClass) - // Key = JA.getKind (); - // else - - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - // if ((JA.getKind () == Action::CompileJobClass) - // && (JA.getType () != types::TY_LTO_BC)) { - // Key = JA.getKind (); - // } - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::InputClass: - case Action::BindArchClass: - assert(0 && "Invalid tool kind."); - case Action::AnalyzeJobClass: - T = new tools::Clang(*this); break; - case Action::AssembleJobClass: - T = new tools::hexagon::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::hexagon::Link(*this); break; - default: - assert(false && "Unsupported action for Hexagon target."); - } - } +} + +Tool *Hexagon_TC::buildAssembler() const { + return new tools::hexagon::Assemble(*this); +} - return *T; +Tool *Hexagon_TC::buildLinker() const { + return new tools::hexagon::Link(*this); } void Hexagon_TC::AddClangSystemIncludeArgs(const ArgList &DriverArgs, @@ -1682,8 +1709,9 @@ StringRef Hexagon_TC::GetTargetCPU(const ArgList &Args) /// all subcommands. See http://tce.cs.tut.fi for our peculiar target. /// Currently does not support anything else but compilation. -TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple& Triple) - : ToolChain(D, Triple) { +TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple& Triple, + const ArgList &Args) + : ToolChain(D, Triple, Args) { // Path mangling to find libexec std::string Path(getDriver().Dir); @@ -1692,9 +1720,6 @@ TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple& Triple) } TCEToolChain::~TCEToolChain() { - for (llvm::DenseMap<unsigned, Tool*>::iterator - it = Tools.begin(), ie = Tools.end(); it != ie; ++it) - delete it->second; } bool TCEToolChain::IsMathErrnoDefault() const { @@ -1705,28 +1730,12 @@ bool TCEToolChain::isPICDefault() const { return false; } -bool TCEToolChain::isPICDefaultForced() const { +bool TCEToolChain::isPIEDefault() const { return false; } -Tool &TCEToolChain::SelectTool(const Compilation &C, - const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - Key = Action::AnalyzeJobClass; - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::PreprocessJobClass: - T = new tools::gcc::Preprocess(*this); break; - case Action::AnalyzeJobClass: - T = new tools::Clang(*this); break; - default: - llvm_unreachable("Unsupported action for TCE target."); - } - } - return *T; +bool TCEToolChain::isPICDefaultForced() const { + return false; } /// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly. @@ -1737,36 +1746,12 @@ OpenBSD::OpenBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Arg getFilePaths().push_back("/usr/lib"); } -Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: { - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::openbsd::Assemble(*this); - break; - } - case Action::LinkJobClass: - T = new tools::openbsd::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *OpenBSD::buildAssembler() const { + return new tools::openbsd::Assemble(*this); +} - return *T; +Tool *OpenBSD::buildLinker() const { + return new tools::openbsd::Link(*this); } /// Bitrig - Bitrig tool chain which can call as(1) and ld(1) directly. @@ -1777,36 +1762,12 @@ Bitrig::Bitrig(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) getFilePaths().push_back("/usr/lib"); } -Tool &Bitrig::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: { - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::bitrig::Assemble(*this); - break; - } - case Action::LinkJobClass: - T = new tools::bitrig::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *Bitrig::buildAssembler() const { + return new tools::bitrig::Assemble(*this); +} - return *T; +Tool *Bitrig::buildLinker() const { + return new tools::bitrig::Link(*this); } void Bitrig::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, @@ -1869,35 +1830,12 @@ FreeBSD::FreeBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Arg getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); } -Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::freebsd::Assemble(*this); - break; - case Action::LinkJobClass: - T = new tools::freebsd::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *FreeBSD::buildAssembler() const { + return new tools::freebsd::Assemble(*this); +} - return *T; +Tool *FreeBSD::buildLinker() const { + return new tools::freebsd::Link(*this); } bool FreeBSD::UseSjLjExceptions() const { @@ -1931,36 +1869,48 @@ NetBSD::NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) } } -Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::netbsd::Assemble(*this); - break; - case Action::LinkJobClass: - T = new tools::netbsd::Link(*this); - break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } +Tool *NetBSD::buildAssembler() const { + return new tools::netbsd::Assemble(*this); +} + +Tool *NetBSD::buildLinker() const { + return new tools::netbsd::Link(*this); +} + +ToolChain::CXXStdlibType +NetBSD::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 *T; + return ToolChain::CST_Libstdcxx; +} + +void NetBSD::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/c++/"); + break; + case ToolChain::CST_Libstdcxx: + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/g++"); + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/g++/backward"); + break; + } } /// Minix - Minix tool chain which can call as(1) and ld(1) directly. @@ -1971,27 +1921,12 @@ Minix::Minix(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) getFilePaths().push_back("/usr/lib"); } -Tool &Minix::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - T = new tools::minix::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::minix::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *Minix::buildAssembler() const { + return new tools::minix::Assemble(*this); +} - return *T; +Tool *Minix::buildLinker() const { + return new tools::minix::Link(*this); } /// AuroraUX - AuroraUX tool chain which can call as(1) and ld(1) directly. @@ -2012,27 +1947,12 @@ AuroraUX::AuroraUX(const Driver &D, const llvm::Triple& Triple, } -Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - T = new tools::auroraux::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::auroraux::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *AuroraUX::buildAssembler() const { + return new tools::auroraux::Assemble(*this); +} - return *T; +Tool *AuroraUX::buildLinker() const { + return new tools::auroraux::Link(*this); } /// Solaris - Solaris tool chain which can call as(1) and ld(1) directly. @@ -2049,32 +1969,17 @@ Solaris::Solaris(const Driver &D, const llvm::Triple& Triple, getFilePaths().push_back("/usr/lib"); } -Tool &Solaris::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - T = new tools::solaris::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::solaris::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *Solaris::buildAssembler() const { + return new tools::solaris::Assemble(*this); +} - return *T; +Tool *Solaris::buildLinker() const { + return new tools::solaris::Link(*this); } -/// Linux toolchain (very bare-bones at the moment). +/// Distribution (very bare-bones at the moment). -enum LinuxDistro { +enum Distro { ArchLinux, DebianLenny, DebianSqueeze, @@ -2107,33 +2012,33 @@ enum LinuxDistro { UnknownDistro }; -static bool IsRedhat(enum LinuxDistro Distro) { +static bool IsRedhat(enum Distro Distro) { return (Distro >= Fedora13 && Distro <= FedoraRawhide) || (Distro >= RHEL4 && Distro <= RHEL6); } -static bool IsOpenSuse(enum LinuxDistro Distro) { +static bool IsOpenSuse(enum Distro Distro) { return Distro >= OpenSuse11_3 && Distro <= OpenSuse12_2; } -static bool IsDebian(enum LinuxDistro Distro) { +static bool IsDebian(enum Distro Distro) { return Distro >= DebianLenny && Distro <= DebianJessie; } -static bool IsUbuntu(enum LinuxDistro Distro) { +static bool IsUbuntu(enum Distro Distro) { return Distro >= UbuntuHardy && Distro <= UbuntuRaring; } -static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { +static Distro DetectDistro(llvm::Triple::ArchType Arch) { OwningPtr<llvm::MemoryBuffer> File; if (!llvm::MemoryBuffer::getFile("/etc/lsb-release", File)) { StringRef Data = File.get()->getBuffer(); SmallVector<StringRef, 8> Lines; Data.split(Lines, "\n"); - LinuxDistro Version = UnknownDistro; + Distro Version = UnknownDistro; for (unsigned i = 0, s = Lines.size(); i != s; ++i) if (Version == UnknownDistro && Lines[i].startswith("DISTRIB_CODENAME=")) - Version = llvm::StringSwitch<LinuxDistro>(Lines[i].substr(17)) + Version = llvm::StringSwitch<Distro>(Lines[i].substr(17)) .Case("hardy", UbuntuHardy) .Case("intrepid", UbuntuIntrepid) .Case("jaunty", UbuntuJaunty) @@ -2190,7 +2095,7 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { } if (!llvm::MemoryBuffer::getFile("/etc/SuSE-release", File)) - return llvm::StringSwitch<LinuxDistro>(File.get()->getBuffer()) + return llvm::StringSwitch<Distro>(File.get()->getBuffer()) .StartsWith("openSUSE 11.3", OpenSuse11_3) .StartsWith("openSUSE 11.4", OpenSuse11_4) .StartsWith("openSUSE 12.1", OpenSuse12_1) @@ -2255,6 +2160,8 @@ static std::string getMultiarchTriple(const llvm::Triple TargetTriple, return "mipsel-linux-gnu"; return TargetTriple.str(); case llvm::Triple::ppc: + if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnuspe")) + return "powerpc-linux-gnuspe"; if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnu")) return "powerpc-linux-gnu"; return TargetTriple.str(); @@ -2269,13 +2176,6 @@ static void addPathIfExists(Twine Path, ToolChain::path_list &Paths) { if (llvm::sys::fs::exists(Path)) Paths.push_back(Path.str()); } -static bool isMipsArch(llvm::Triple::ArchType Arch) { - return Arch == llvm::Triple::mips || - Arch == llvm::Triple::mipsel || - Arch == llvm::Triple::mips64 || - Arch == llvm::Triple::mips64el; -} - static bool isMipsR2Arch(llvm::Triple::ArchType Arch, const ArgList &Args) { if (Arch != llvm::Triple::mips && @@ -2312,7 +2212,7 @@ static StringRef getMultilibDir(const llvm::Triple &Triple, Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { llvm::Triple::ArchType Arch = Triple.getArch(); - const std::string &SysRoot = getDriver().SysRoot; + std::string SysRoot = computeSysRoot(Args); // OpenSuse stores the linker with the compiler, add that to the search // path. @@ -2322,7 +2222,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) Linker = GetProgramPath("ld"); - LinuxDistro Distro = DetectLinuxDistro(Arch); + Distro Distro = DetectDistro(Arch); if (IsOpenSuse(Distro) || IsUbuntu(Distro)) { ExtraOpts.push_back("-z"); @@ -2333,13 +2233,17 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) ExtraOpts.push_back("-X"); const bool IsAndroid = Triple.getEnvironment() == llvm::Triple::Android; + const bool IsMips = isMipsArch(Arch); + + if (IsMips && !SysRoot.empty()) + ExtraOpts.push_back("--sysroot=" + SysRoot); // Do not use 'gnu' hash style for Mips targets because .gnu.hash // and the MIPS ABI require .dynsym to be sorted in different ways. // .gnu.hash needs symbols to be grouped by hash code whereas the MIPS // ABI requires a mapping between the GOT and the symbol table. // Android loader does not support .gnu.hash. - if (!isMipsArch(Arch) && !IsAndroid) { + if (!IsMips && !IsAndroid) { if (IsRedhat(Distro) || IsOpenSuse(Distro) || (IsUbuntu(Distro) && Distro >= UbuntuMaverick)) ExtraOpts.push_back("--hash-style=gnu"); @@ -2404,6 +2308,15 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) if (IsAndroid) { addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib", Paths); } + // Sourcery CodeBench MIPS toolchain holds some libraries under + // the parent prefix of the GCC installation. + if (IsMips) { + std::string Suffix; + appendMipsTargetSuffix(Suffix, Arch, Args); + addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + + Multilib + Suffix, + Paths); + } } addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths); addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths); @@ -2430,41 +2343,20 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) } addPathIfExists(SysRoot + "/lib", Paths); addPathIfExists(SysRoot + "/usr/lib", Paths); + + IsPIEDefault = SanitizerArgs(*this, Args).hasZeroBaseShadow(); } bool Linux::HasNativeLLVMSupport() const { return true; } -Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, - options::OPT_no_integrated_as, - IsIntegratedAssemblerDefault()); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - if (UseIntegratedAs) - T = new tools::ClangAs(*this); - else - T = new tools::linuxtools::Assemble(*this); - break; - case Action::LinkJobClass: - T = new tools::linuxtools::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *Linux::buildLinker() const { + return new tools::gnutools::Link(*this); +} - return *T; +Tool *Linux::buildAssembler() const { + return new tools::gnutools::Assemble(*this); } void Linux::addClangTargetOptions(const ArgList &DriverArgs, @@ -2480,15 +2372,31 @@ void Linux::addClangTargetOptions(const ArgList &DriverArgs, CC1Args.push_back("-fuse-init-array"); } +std::string Linux::computeSysRoot(const ArgList &Args) const { + if (!getDriver().SysRoot.empty()) + return getDriver().SysRoot; + + if (!GCCInstallation.isValid() || !isMipsArch(getTriple().getArch())) + return std::string(); + + std::string Path = + (GCCInstallation.getInstallPath() + + "/../../../../" + GCCInstallation.getTriple().str() + "/libc").str(); + appendMipsTargetSuffix(Path, getTriple().getArch(), Args); + + return llvm::sys::fs::exists(Path) ? Path : ""; +} + void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { const Driver &D = getDriver(); + std::string SysRoot = computeSysRoot(DriverArgs); if (DriverArgs.hasArg(options::OPT_nostdinc)) return; if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) - addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/local/include"); + addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include"); if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { llvm::sys::Path P(D.ResourceDir); @@ -2506,7 +2414,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, CIncludeDirs.split(dirs, ":"); for (SmallVectorImpl<StringRef>::iterator I = dirs.begin(), E = dirs.end(); I != E; ++I) { - StringRef Prefix = llvm::sys::path::is_absolute(*I) ? D.SysRoot : ""; + StringRef Prefix = llvm::sys::path::is_absolute(*I) ? SysRoot : ""; addExternCSystemInclude(DriverArgs, CC1Args, Prefix + *I); } return; @@ -2515,6 +2423,20 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // Lacking those, try to detect the correct set of system includes for the // target triple. + // Sourcery CodeBench and modern FSF Mips toolchains put extern C + // system includes under three additional directories. + if (GCCInstallation.isValid() && isMipsArch(getTriple().getArch())) { + addExternCSystemIncludeIfExists(DriverArgs, CC1Args, + GCCInstallation.getInstallPath() + + "/include"); + + addExternCSystemIncludeIfExists(DriverArgs, CC1Args, + GCCInstallation.getInstallPath() + + "/../../../../" + + GCCInstallation.getTriple().str() + + "/libc/usr/include"); + } + // Implement generic Debian multiarch support. const StringRef X86_64MultiarchIncludeDirs[] = { "/usr/include/x86_64-linux-gnu", @@ -2580,8 +2502,8 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, for (ArrayRef<StringRef>::iterator I = MultiarchIncludeDirs.begin(), E = MultiarchIncludeDirs.end(); I != E; ++I) { - if (llvm::sys::fs::exists(D.SysRoot + *I)) { - addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + *I); + if (llvm::sys::fs::exists(SysRoot + *I)) { + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + *I); break; } } @@ -2592,9 +2514,9 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // 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, D.SysRoot + "/include"); + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include"); - addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include"); + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); } /// \brief Helper to add the three variant paths for a libstdc++ installation. @@ -2678,6 +2600,10 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, } } +bool Linux::isPIEDefault() const { + return IsPIEDefault; +} + /// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly. DragonFly::DragonFly(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) @@ -2690,28 +2616,16 @@ DragonFly::DragonFly(const Driver &D, const llvm::Triple& Triple, const ArgList getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); - getFilePaths().push_back("/usr/lib/gcc41"); + if (llvm::sys::fs::exists("/usr/lib/gcc47")) + getFilePaths().push_back("/usr/lib/gcc47"); + else + getFilePaths().push_back("/usr/lib/gcc44"); } -Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA, - const ActionList &Inputs) const { - Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else - Key = JA.getKind(); - - Tool *&T = Tools[Key]; - if (!T) { - switch (Key) { - case Action::AssembleJobClass: - T = new tools::dragonfly::Assemble(*this); break; - case Action::LinkJobClass: - T = new tools::dragonfly::Link(*this); break; - default: - T = &Generic_GCC::SelectTool(C, JA, Inputs); - } - } +Tool *DragonFly::buildAssembler() const { + return new tools::dragonfly::Assemble(*this); +} - return *T; +Tool *DragonFly::buildLinker() const { + return new tools::dragonfly::Link(*this); } |