10b57cec5SDimitry Andric //===--- Solaris.cpp - Solaris ToolChain Implementations --------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "Solaris.h" 100b57cec5SDimitry Andric #include "CommonArgs.h" 11a7dea167SDimitry Andric #include "clang/Basic/LangStandard.h" 120b57cec5SDimitry Andric #include "clang/Config/config.h" 130b57cec5SDimitry Andric #include "clang/Driver/Compilation.h" 140b57cec5SDimitry Andric #include "clang/Driver/Driver.h" 150b57cec5SDimitry Andric #include "clang/Driver/DriverDiagnostic.h" 160b57cec5SDimitry Andric #include "clang/Driver/Options.h" 170b57cec5SDimitry Andric #include "llvm/Option/ArgList.h" 180b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 190b57cec5SDimitry Andric #include "llvm/Support/Path.h" 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric using namespace clang::driver; 220b57cec5SDimitry Andric using namespace clang::driver::tools; 230b57cec5SDimitry Andric using namespace clang::driver::toolchains; 240b57cec5SDimitry Andric using namespace clang; 250b57cec5SDimitry Andric using namespace llvm::opt; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA, 280b57cec5SDimitry Andric const InputInfo &Output, 290b57cec5SDimitry Andric const InputInfoList &Inputs, 300b57cec5SDimitry Andric const ArgList &Args, 310b57cec5SDimitry Andric const char *LinkingOutput) const { 320b57cec5SDimitry Andric claimNoWarnArgs(Args); 330b57cec5SDimitry Andric ArgStringList CmdArgs; 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric CmdArgs.push_back("-o"); 380b57cec5SDimitry Andric CmdArgs.push_back(Output.getFilename()); 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric for (const auto &II : Inputs) 410b57cec5SDimitry Andric CmdArgs.push_back(II.getFilename()); 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); 445ffd83dbSDimitry Andric C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), 45e8d8bef9SDimitry Andric Exec, CmdArgs, Inputs, Output)); 460b57cec5SDimitry Andric } 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, 490b57cec5SDimitry Andric const InputInfo &Output, 500b57cec5SDimitry Andric const InputInfoList &Inputs, 510b57cec5SDimitry Andric const ArgList &Args, 520b57cec5SDimitry Andric const char *LinkingOutput) const { 530b57cec5SDimitry Andric ArgStringList CmdArgs; 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric // Demangle C++ names in errors 560b57cec5SDimitry Andric CmdArgs.push_back("-C"); 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) { 590b57cec5SDimitry Andric CmdArgs.push_back("-e"); 600b57cec5SDimitry Andric CmdArgs.push_back("_start"); 610b57cec5SDimitry Andric } 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric if (Args.hasArg(options::OPT_static)) { 640b57cec5SDimitry Andric CmdArgs.push_back("-Bstatic"); 650b57cec5SDimitry Andric CmdArgs.push_back("-dn"); 660b57cec5SDimitry Andric } else { 670b57cec5SDimitry Andric CmdArgs.push_back("-Bdynamic"); 680b57cec5SDimitry Andric if (Args.hasArg(options::OPT_shared)) { 690b57cec5SDimitry Andric CmdArgs.push_back("-shared"); 700b57cec5SDimitry Andric } 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric // libpthread has been folded into libc since Solaris 10, no need to do 730b57cec5SDimitry Andric // anything for pthreads. Claim argument to avoid warning. 740b57cec5SDimitry Andric Args.ClaimAllArgs(options::OPT_pthread); 750b57cec5SDimitry Andric Args.ClaimAllArgs(options::OPT_pthreads); 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric if (Output.isFilename()) { 790b57cec5SDimitry Andric CmdArgs.push_back("-o"); 800b57cec5SDimitry Andric CmdArgs.push_back(Output.getFilename()); 810b57cec5SDimitry Andric } else { 820b57cec5SDimitry Andric assert(Output.isNothing() && "Invalid output."); 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric 85*2a66634dSDimitry Andric if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, 86*2a66634dSDimitry Andric options::OPT_r)) { 870b57cec5SDimitry Andric if (!Args.hasArg(options::OPT_shared)) 880b57cec5SDimitry Andric CmdArgs.push_back( 890b57cec5SDimitry Andric Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); 92a7dea167SDimitry Andric 93a7dea167SDimitry Andric const Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi); 94a7dea167SDimitry Andric bool HaveAnsi = false; 95a7dea167SDimitry Andric const LangStandard *LangStd = nullptr; 96a7dea167SDimitry Andric if (Std) { 97a7dea167SDimitry Andric HaveAnsi = Std->getOption().matches(options::OPT_ansi); 98a7dea167SDimitry Andric if (!HaveAnsi) 99a7dea167SDimitry Andric LangStd = LangStandard::getLangStandardForName(Std->getValue()); 100a7dea167SDimitry Andric } 101a7dea167SDimitry Andric 102a7dea167SDimitry Andric const char *values_X = "values-Xa.o"; 103a7dea167SDimitry Andric // Use values-Xc.o for -ansi, -std=c*, -std=iso9899:199409. 104a7dea167SDimitry Andric if (HaveAnsi || (LangStd && !LangStd->isGNUMode())) 105a7dea167SDimitry Andric values_X = "values-Xc.o"; 106a7dea167SDimitry Andric CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(values_X))); 107a7dea167SDimitry Andric 108a7dea167SDimitry Andric const char *values_xpg = "values-xpg6.o"; 109a7dea167SDimitry Andric // Use values-xpg4.o for -std=c90, -std=gnu90, -std=iso9899:199409. 110a7dea167SDimitry Andric if (LangStd && LangStd->getLanguage() == Language::C && !LangStd->isC99()) 111a7dea167SDimitry Andric values_xpg = "values-xpg4.o"; 1120b57cec5SDimitry Andric CmdArgs.push_back( 113a7dea167SDimitry Andric Args.MakeArgString(getToolChain().GetFilePath(values_xpg))); 1140b57cec5SDimitry Andric CmdArgs.push_back( 1150b57cec5SDimitry Andric Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric getToolChain().AddFilePathLibArgs(Args, CmdArgs); 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, 1210b57cec5SDimitry Andric options::OPT_e, options::OPT_r}); 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric bool NeedsSanitizerDeps = addSanitizerRuntimes(getToolChain(), Args, CmdArgs); 1240b57cec5SDimitry Andric AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); 1250b57cec5SDimitry Andric 126*2a66634dSDimitry Andric if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, 127*2a66634dSDimitry Andric options::OPT_r)) { 1280b57cec5SDimitry Andric if (getToolChain().ShouldLinkCXXStdlib(Args)) 1290b57cec5SDimitry Andric getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); 1300b57cec5SDimitry Andric if (Args.hasArg(options::OPT_fstack_protector) || 1310b57cec5SDimitry Andric Args.hasArg(options::OPT_fstack_protector_strong) || 1320b57cec5SDimitry Andric Args.hasArg(options::OPT_fstack_protector_all)) { 1330b57cec5SDimitry Andric // Explicitly link ssp libraries, not folded into Solaris libc. 1340b57cec5SDimitry Andric CmdArgs.push_back("-lssp_nonshared"); 1350b57cec5SDimitry Andric CmdArgs.push_back("-lssp"); 1360b57cec5SDimitry Andric } 137d781ede6SDimitry Andric // LLVM support for atomics on 32-bit SPARC V8+ is incomplete, so 138d781ede6SDimitry Andric // forcibly link with libatomic as a workaround. 139d781ede6SDimitry Andric if (getToolChain().getTriple().getArch() == llvm::Triple::sparc) { 140d781ede6SDimitry Andric CmdArgs.push_back(getAsNeededOption(getToolChain(), true)); 141d781ede6SDimitry Andric CmdArgs.push_back("-latomic"); 142d781ede6SDimitry Andric CmdArgs.push_back(getAsNeededOption(getToolChain(), false)); 143d781ede6SDimitry Andric } 1440b57cec5SDimitry Andric CmdArgs.push_back("-lgcc_s"); 1450b57cec5SDimitry Andric CmdArgs.push_back("-lc"); 1460b57cec5SDimitry Andric if (!Args.hasArg(options::OPT_shared)) { 1470b57cec5SDimitry Andric CmdArgs.push_back("-lgcc"); 1480b57cec5SDimitry Andric CmdArgs.push_back("-lm"); 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric if (NeedsSanitizerDeps) 1510b57cec5SDimitry Andric linkSanitizerRuntimeDeps(getToolChain(), CmdArgs); 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 154*2a66634dSDimitry Andric if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, 155*2a66634dSDimitry Andric options::OPT_r)) { 1560b57cec5SDimitry Andric CmdArgs.push_back( 1570b57cec5SDimitry Andric Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); 158*2a66634dSDimitry Andric CmdArgs.push_back( 159*2a66634dSDimitry Andric Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric getToolChain().addProfileRTLibs(Args, CmdArgs); 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); 1655ffd83dbSDimitry Andric C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), 166e8d8bef9SDimitry Andric Exec, CmdArgs, Inputs, Output)); 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric 1690b57cec5SDimitry Andric static StringRef getSolarisLibSuffix(const llvm::Triple &Triple) { 1700b57cec5SDimitry Andric switch (Triple.getArch()) { 1710b57cec5SDimitry Andric case llvm::Triple::x86: 1720b57cec5SDimitry Andric case llvm::Triple::sparc: 1730b57cec5SDimitry Andric break; 1740b57cec5SDimitry Andric case llvm::Triple::x86_64: 1750b57cec5SDimitry Andric return "/amd64"; 1760b57cec5SDimitry Andric case llvm::Triple::sparcv9: 1770b57cec5SDimitry Andric return "/sparcv9"; 1780b57cec5SDimitry Andric default: 1790b57cec5SDimitry Andric llvm_unreachable("Unsupported architecture"); 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric return ""; 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric /// Solaris - Solaris tool chain which can call as(1) and ld(1) directly. 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric Solaris::Solaris(const Driver &D, const llvm::Triple &Triple, 1870b57cec5SDimitry Andric const ArgList &Args) 1880b57cec5SDimitry Andric : Generic_ELF(D, Triple, Args) { 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric GCCInstallation.init(Triple, Args); 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric StringRef LibSuffix = getSolarisLibSuffix(Triple); 1930b57cec5SDimitry Andric path_list &Paths = getFilePaths(); 1940b57cec5SDimitry Andric if (GCCInstallation.isValid()) { 1950b57cec5SDimitry Andric // On Solaris gcc uses both an architecture-specific path with triple in it 1960b57cec5SDimitry Andric // as well as a more generic lib path (+arch suffix). 1970b57cec5SDimitry Andric addPathIfExists(D, 1980b57cec5SDimitry Andric GCCInstallation.getInstallPath() + 1990b57cec5SDimitry Andric GCCInstallation.getMultilib().gccSuffix(), 2000b57cec5SDimitry Andric Paths); 2010b57cec5SDimitry Andric addPathIfExists(D, GCCInstallation.getParentLibPath() + LibSuffix, Paths); 2020b57cec5SDimitry Andric } 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric // If we are currently running Clang inside of the requested system root, 2050b57cec5SDimitry Andric // add its parent library path to those searched. 2060b57cec5SDimitry Andric if (StringRef(D.Dir).startswith(D.SysRoot)) 2070b57cec5SDimitry Andric addPathIfExists(D, D.Dir + "/../lib", Paths); 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric addPathIfExists(D, D.SysRoot + "/usr/lib" + LibSuffix, Paths); 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric SanitizerMask Solaris::getSupportedSanitizers() const { 2130b57cec5SDimitry Andric const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; 214a7dea167SDimitry Andric const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; 2150b57cec5SDimitry Andric SanitizerMask Res = ToolChain::getSupportedSanitizers(); 2160b57cec5SDimitry Andric // FIXME: Omit X86_64 until 64-bit support is figured out. 2170b57cec5SDimitry Andric if (IsX86) { 2180b57cec5SDimitry Andric Res |= SanitizerKind::Address; 2190b57cec5SDimitry Andric Res |= SanitizerKind::PointerCompare; 2200b57cec5SDimitry Andric Res |= SanitizerKind::PointerSubtract; 2210b57cec5SDimitry Andric } 222a7dea167SDimitry Andric if (IsX86 || IsX86_64) 223a7dea167SDimitry Andric Res |= SanitizerKind::Function; 2240b57cec5SDimitry Andric Res |= SanitizerKind::Vptr; 2250b57cec5SDimitry Andric return Res; 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric Tool *Solaris::buildAssembler() const { 2290b57cec5SDimitry Andric return new tools::solaris::Assembler(*this); 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric Tool *Solaris::buildLinker() const { return new tools::solaris::Linker(*this); } 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric void Solaris::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 2350b57cec5SDimitry Andric ArgStringList &CC1Args) const { 2360b57cec5SDimitry Andric const Driver &D = getDriver(); 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) 2390b57cec5SDimitry Andric return; 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) 2420b57cec5SDimitry Andric addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/local/include"); 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { 2450b57cec5SDimitry Andric SmallString<128> P(D.ResourceDir); 2460b57cec5SDimitry Andric llvm::sys::path::append(P, "include"); 2470b57cec5SDimitry Andric addSystemInclude(DriverArgs, CC1Args, P); 2480b57cec5SDimitry Andric } 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric if (DriverArgs.hasArg(options::OPT_nostdlibinc)) 2510b57cec5SDimitry Andric return; 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric // Check for configure-time C include directories. 2540b57cec5SDimitry Andric StringRef CIncludeDirs(C_INCLUDE_DIRS); 2550b57cec5SDimitry Andric if (CIncludeDirs != "") { 2560b57cec5SDimitry Andric SmallVector<StringRef, 5> dirs; 2570b57cec5SDimitry Andric CIncludeDirs.split(dirs, ":"); 2580b57cec5SDimitry Andric for (StringRef dir : dirs) { 2590b57cec5SDimitry Andric StringRef Prefix = 2605ffd83dbSDimitry Andric llvm::sys::path::is_absolute(dir) ? "" : StringRef(D.SysRoot); 2610b57cec5SDimitry Andric addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); 2620b57cec5SDimitry Andric } 2630b57cec5SDimitry Andric return; 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric 2660b57cec5SDimitry Andric // Add include directories specific to the selected multilib set and multilib. 2670b57cec5SDimitry Andric if (GCCInstallation.isValid()) { 2680b57cec5SDimitry Andric const MultilibSet::IncludeDirsFunc &Callback = 2690b57cec5SDimitry Andric Multilibs.includeDirsCallback(); 2700b57cec5SDimitry Andric if (Callback) { 2710b57cec5SDimitry Andric for (const auto &Path : Callback(GCCInstallation.getMultilib())) 2720b57cec5SDimitry Andric addExternCSystemIncludeIfExists( 2730b57cec5SDimitry Andric DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path); 2740b57cec5SDimitry Andric } 2750b57cec5SDimitry Andric } 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include"); 2780b57cec5SDimitry Andric } 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric void Solaris::addLibStdCxxIncludePaths( 2810b57cec5SDimitry Andric const llvm::opt::ArgList &DriverArgs, 2820b57cec5SDimitry Andric llvm::opt::ArgStringList &CC1Args) const { 2830b57cec5SDimitry Andric // We need a detected GCC installation on Solaris (similar to Linux) 2840b57cec5SDimitry Andric // to provide libstdc++'s headers. 2850b57cec5SDimitry Andric if (!GCCInstallation.isValid()) 2860b57cec5SDimitry Andric return; 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric // By default, look for the C++ headers in an include directory adjacent to 2890b57cec5SDimitry Andric // the lib directory of the GCC installation. 2900b57cec5SDimitry Andric // On Solaris this usually looks like /usr/gcc/X.Y/include/c++/X.Y.Z 2910b57cec5SDimitry Andric StringRef LibDir = GCCInstallation.getParentLibPath(); 2920b57cec5SDimitry Andric StringRef TripleStr = GCCInstallation.getTriple().str(); 2930b57cec5SDimitry Andric const Multilib &Multilib = GCCInstallation.getMultilib(); 2940b57cec5SDimitry Andric const GCCVersion &Version = GCCInstallation.getVersion(); 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric // The primary search for libstdc++ supports multiarch variants. 297fe6060f1SDimitry Andric addLibStdCXXIncludePaths(LibDir.str() + "/../include/c++/" + Version.Text, 298fe6060f1SDimitry Andric TripleStr, Multilib.includeSuffix(), DriverArgs, 299fe6060f1SDimitry Andric CC1Args); 3000b57cec5SDimitry Andric } 301