106f32e7eSjoerg //===--- Solaris.cpp - Solaris ToolChain Implementations --------*- C++ -*-===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg 
906f32e7eSjoerg #include "Solaris.h"
1006f32e7eSjoerg #include "CommonArgs.h"
1106f32e7eSjoerg #include "clang/Basic/LangStandard.h"
1206f32e7eSjoerg #include "clang/Config/config.h"
1306f32e7eSjoerg #include "clang/Driver/Compilation.h"
1406f32e7eSjoerg #include "clang/Driver/Driver.h"
1506f32e7eSjoerg #include "clang/Driver/DriverDiagnostic.h"
1606f32e7eSjoerg #include "clang/Driver/Options.h"
1706f32e7eSjoerg #include "llvm/Option/ArgList.h"
1806f32e7eSjoerg #include "llvm/Support/FileSystem.h"
1906f32e7eSjoerg #include "llvm/Support/Path.h"
2006f32e7eSjoerg 
2106f32e7eSjoerg using namespace clang::driver;
2206f32e7eSjoerg using namespace clang::driver::tools;
2306f32e7eSjoerg using namespace clang::driver::toolchains;
2406f32e7eSjoerg using namespace clang;
2506f32e7eSjoerg using namespace llvm::opt;
2606f32e7eSjoerg 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const2706f32e7eSjoerg void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
2806f32e7eSjoerg                                       const InputInfo &Output,
2906f32e7eSjoerg                                       const InputInfoList &Inputs,
3006f32e7eSjoerg                                       const ArgList &Args,
3106f32e7eSjoerg                                       const char *LinkingOutput) const {
3206f32e7eSjoerg   claimNoWarnArgs(Args);
3306f32e7eSjoerg   ArgStringList CmdArgs;
3406f32e7eSjoerg 
3506f32e7eSjoerg   Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
3606f32e7eSjoerg 
3706f32e7eSjoerg   CmdArgs.push_back("-o");
3806f32e7eSjoerg   CmdArgs.push_back(Output.getFilename());
3906f32e7eSjoerg 
4006f32e7eSjoerg   for (const auto &II : Inputs)
4106f32e7eSjoerg     CmdArgs.push_back(II.getFilename());
4206f32e7eSjoerg 
4306f32e7eSjoerg   const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
44*13fbcb42Sjoerg   C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
45*13fbcb42Sjoerg                                          Exec, CmdArgs, Inputs, Output));
4606f32e7eSjoerg }
4706f32e7eSjoerg 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const4806f32e7eSjoerg void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
4906f32e7eSjoerg                                    const InputInfo &Output,
5006f32e7eSjoerg                                    const InputInfoList &Inputs,
5106f32e7eSjoerg                                    const ArgList &Args,
5206f32e7eSjoerg                                    const char *LinkingOutput) const {
5306f32e7eSjoerg   ArgStringList CmdArgs;
5406f32e7eSjoerg 
5506f32e7eSjoerg   // Demangle C++ names in errors
5606f32e7eSjoerg   CmdArgs.push_back("-C");
5706f32e7eSjoerg 
5806f32e7eSjoerg   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
5906f32e7eSjoerg     CmdArgs.push_back("-e");
6006f32e7eSjoerg     CmdArgs.push_back("_start");
6106f32e7eSjoerg   }
6206f32e7eSjoerg 
6306f32e7eSjoerg   if (Args.hasArg(options::OPT_static)) {
6406f32e7eSjoerg     CmdArgs.push_back("-Bstatic");
6506f32e7eSjoerg     CmdArgs.push_back("-dn");
6606f32e7eSjoerg   } else {
6706f32e7eSjoerg     CmdArgs.push_back("-Bdynamic");
6806f32e7eSjoerg     if (Args.hasArg(options::OPT_shared)) {
6906f32e7eSjoerg       CmdArgs.push_back("-shared");
7006f32e7eSjoerg     }
7106f32e7eSjoerg 
7206f32e7eSjoerg     // libpthread has been folded into libc since Solaris 10, no need to do
7306f32e7eSjoerg     // anything for pthreads. Claim argument to avoid warning.
7406f32e7eSjoerg     Args.ClaimAllArgs(options::OPT_pthread);
7506f32e7eSjoerg     Args.ClaimAllArgs(options::OPT_pthreads);
7606f32e7eSjoerg   }
7706f32e7eSjoerg 
7806f32e7eSjoerg   if (Output.isFilename()) {
7906f32e7eSjoerg     CmdArgs.push_back("-o");
8006f32e7eSjoerg     CmdArgs.push_back(Output.getFilename());
8106f32e7eSjoerg   } else {
8206f32e7eSjoerg     assert(Output.isNothing() && "Invalid output.");
8306f32e7eSjoerg   }
8406f32e7eSjoerg 
8506f32e7eSjoerg   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
8606f32e7eSjoerg     if (!Args.hasArg(options::OPT_shared))
8706f32e7eSjoerg       CmdArgs.push_back(
8806f32e7eSjoerg           Args.MakeArgString(getToolChain().GetFilePath("crt1.o")));
8906f32e7eSjoerg 
9006f32e7eSjoerg     CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
9106f32e7eSjoerg 
9206f32e7eSjoerg     const Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi);
9306f32e7eSjoerg     bool HaveAnsi = false;
9406f32e7eSjoerg     const LangStandard *LangStd = nullptr;
9506f32e7eSjoerg     if (Std) {
9606f32e7eSjoerg       HaveAnsi = Std->getOption().matches(options::OPT_ansi);
9706f32e7eSjoerg       if (!HaveAnsi)
9806f32e7eSjoerg         LangStd = LangStandard::getLangStandardForName(Std->getValue());
9906f32e7eSjoerg     }
10006f32e7eSjoerg 
10106f32e7eSjoerg     const char *values_X = "values-Xa.o";
10206f32e7eSjoerg     // Use values-Xc.o for -ansi, -std=c*, -std=iso9899:199409.
10306f32e7eSjoerg     if (HaveAnsi || (LangStd && !LangStd->isGNUMode()))
10406f32e7eSjoerg       values_X = "values-Xc.o";
10506f32e7eSjoerg     CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(values_X)));
10606f32e7eSjoerg 
10706f32e7eSjoerg     const char *values_xpg = "values-xpg6.o";
10806f32e7eSjoerg     // Use values-xpg4.o for -std=c90, -std=gnu90, -std=iso9899:199409.
10906f32e7eSjoerg     if (LangStd && LangStd->getLanguage() == Language::C && !LangStd->isC99())
11006f32e7eSjoerg       values_xpg = "values-xpg4.o";
11106f32e7eSjoerg     CmdArgs.push_back(
11206f32e7eSjoerg         Args.MakeArgString(getToolChain().GetFilePath(values_xpg)));
11306f32e7eSjoerg     CmdArgs.push_back(
11406f32e7eSjoerg         Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
11506f32e7eSjoerg   }
11606f32e7eSjoerg 
11706f32e7eSjoerg   getToolChain().AddFilePathLibArgs(Args, CmdArgs);
11806f32e7eSjoerg 
11906f32e7eSjoerg   Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
12006f32e7eSjoerg                             options::OPT_e, options::OPT_r});
12106f32e7eSjoerg 
12206f32e7eSjoerg   bool NeedsSanitizerDeps = addSanitizerRuntimes(getToolChain(), Args, CmdArgs);
12306f32e7eSjoerg   AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
12406f32e7eSjoerg 
12506f32e7eSjoerg   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
12606f32e7eSjoerg     if (getToolChain().ShouldLinkCXXStdlib(Args))
12706f32e7eSjoerg       getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
12806f32e7eSjoerg     if (Args.hasArg(options::OPT_fstack_protector) ||
12906f32e7eSjoerg         Args.hasArg(options::OPT_fstack_protector_strong) ||
13006f32e7eSjoerg         Args.hasArg(options::OPT_fstack_protector_all)) {
13106f32e7eSjoerg       // Explicitly link ssp libraries, not folded into Solaris libc.
13206f32e7eSjoerg       CmdArgs.push_back("-lssp_nonshared");
13306f32e7eSjoerg       CmdArgs.push_back("-lssp");
13406f32e7eSjoerg     }
13506f32e7eSjoerg     CmdArgs.push_back("-lgcc_s");
13606f32e7eSjoerg     CmdArgs.push_back("-lc");
13706f32e7eSjoerg     if (!Args.hasArg(options::OPT_shared)) {
13806f32e7eSjoerg       CmdArgs.push_back("-lgcc");
13906f32e7eSjoerg       CmdArgs.push_back("-lm");
14006f32e7eSjoerg     }
14106f32e7eSjoerg     if (NeedsSanitizerDeps)
14206f32e7eSjoerg       linkSanitizerRuntimeDeps(getToolChain(), CmdArgs);
14306f32e7eSjoerg   }
14406f32e7eSjoerg 
14506f32e7eSjoerg   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
14606f32e7eSjoerg     CmdArgs.push_back(
14706f32e7eSjoerg         Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
14806f32e7eSjoerg   }
14906f32e7eSjoerg   CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
15006f32e7eSjoerg 
15106f32e7eSjoerg   getToolChain().addProfileRTLibs(Args, CmdArgs);
15206f32e7eSjoerg 
15306f32e7eSjoerg   const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
154*13fbcb42Sjoerg   C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
155*13fbcb42Sjoerg                                          Exec, CmdArgs, Inputs, Output));
15606f32e7eSjoerg }
15706f32e7eSjoerg 
getSolarisLibSuffix(const llvm::Triple & Triple)15806f32e7eSjoerg static StringRef getSolarisLibSuffix(const llvm::Triple &Triple) {
15906f32e7eSjoerg   switch (Triple.getArch()) {
16006f32e7eSjoerg   case llvm::Triple::x86:
16106f32e7eSjoerg   case llvm::Triple::sparc:
16206f32e7eSjoerg     break;
16306f32e7eSjoerg   case llvm::Triple::x86_64:
16406f32e7eSjoerg     return "/amd64";
16506f32e7eSjoerg   case llvm::Triple::sparcv9:
16606f32e7eSjoerg     return "/sparcv9";
16706f32e7eSjoerg   default:
16806f32e7eSjoerg     llvm_unreachable("Unsupported architecture");
16906f32e7eSjoerg   }
17006f32e7eSjoerg   return "";
17106f32e7eSjoerg }
17206f32e7eSjoerg 
17306f32e7eSjoerg /// Solaris - Solaris tool chain which can call as(1) and ld(1) directly.
17406f32e7eSjoerg 
Solaris(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)17506f32e7eSjoerg Solaris::Solaris(const Driver &D, const llvm::Triple &Triple,
17606f32e7eSjoerg                  const ArgList &Args)
17706f32e7eSjoerg     : Generic_ELF(D, Triple, Args) {
17806f32e7eSjoerg 
17906f32e7eSjoerg   GCCInstallation.init(Triple, Args);
18006f32e7eSjoerg 
18106f32e7eSjoerg   StringRef LibSuffix = getSolarisLibSuffix(Triple);
18206f32e7eSjoerg   path_list &Paths = getFilePaths();
18306f32e7eSjoerg   if (GCCInstallation.isValid()) {
18406f32e7eSjoerg     // On Solaris gcc uses both an architecture-specific path with triple in it
18506f32e7eSjoerg     // as well as a more generic lib path (+arch suffix).
18606f32e7eSjoerg     addPathIfExists(D,
18706f32e7eSjoerg                     GCCInstallation.getInstallPath() +
18806f32e7eSjoerg                         GCCInstallation.getMultilib().gccSuffix(),
18906f32e7eSjoerg                     Paths);
19006f32e7eSjoerg     addPathIfExists(D, GCCInstallation.getParentLibPath() + LibSuffix, Paths);
19106f32e7eSjoerg   }
19206f32e7eSjoerg 
19306f32e7eSjoerg   // If we are currently running Clang inside of the requested system root,
19406f32e7eSjoerg   // add its parent library path to those searched.
19506f32e7eSjoerg   if (StringRef(D.Dir).startswith(D.SysRoot))
19606f32e7eSjoerg     addPathIfExists(D, D.Dir + "/../lib", Paths);
19706f32e7eSjoerg 
19806f32e7eSjoerg   addPathIfExists(D, D.SysRoot + "/usr/lib" + LibSuffix, Paths);
19906f32e7eSjoerg }
20006f32e7eSjoerg 
getSupportedSanitizers() const20106f32e7eSjoerg SanitizerMask Solaris::getSupportedSanitizers() const {
20206f32e7eSjoerg   const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
20306f32e7eSjoerg   const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
20406f32e7eSjoerg   SanitizerMask Res = ToolChain::getSupportedSanitizers();
20506f32e7eSjoerg   // FIXME: Omit X86_64 until 64-bit support is figured out.
20606f32e7eSjoerg   if (IsX86) {
20706f32e7eSjoerg     Res |= SanitizerKind::Address;
20806f32e7eSjoerg     Res |= SanitizerKind::PointerCompare;
20906f32e7eSjoerg     Res |= SanitizerKind::PointerSubtract;
21006f32e7eSjoerg   }
21106f32e7eSjoerg   if (IsX86 || IsX86_64)
21206f32e7eSjoerg     Res |= SanitizerKind::Function;
21306f32e7eSjoerg   Res |= SanitizerKind::Vptr;
21406f32e7eSjoerg   return Res;
21506f32e7eSjoerg }
21606f32e7eSjoerg 
buildAssembler() const21706f32e7eSjoerg Tool *Solaris::buildAssembler() const {
21806f32e7eSjoerg   return new tools::solaris::Assembler(*this);
21906f32e7eSjoerg }
22006f32e7eSjoerg 
buildLinker() const22106f32e7eSjoerg Tool *Solaris::buildLinker() const { return new tools::solaris::Linker(*this); }
22206f32e7eSjoerg 
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const22306f32e7eSjoerg void Solaris::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
22406f32e7eSjoerg                                         ArgStringList &CC1Args) const {
22506f32e7eSjoerg   const Driver &D = getDriver();
22606f32e7eSjoerg 
22706f32e7eSjoerg   if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
22806f32e7eSjoerg     return;
22906f32e7eSjoerg 
23006f32e7eSjoerg   if (!DriverArgs.hasArg(options::OPT_nostdlibinc))
23106f32e7eSjoerg     addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/local/include");
23206f32e7eSjoerg 
23306f32e7eSjoerg   if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
23406f32e7eSjoerg     SmallString<128> P(D.ResourceDir);
23506f32e7eSjoerg     llvm::sys::path::append(P, "include");
23606f32e7eSjoerg     addSystemInclude(DriverArgs, CC1Args, P);
23706f32e7eSjoerg   }
23806f32e7eSjoerg 
23906f32e7eSjoerg   if (DriverArgs.hasArg(options::OPT_nostdlibinc))
24006f32e7eSjoerg     return;
24106f32e7eSjoerg 
24206f32e7eSjoerg   // Check for configure-time C include directories.
24306f32e7eSjoerg   StringRef CIncludeDirs(C_INCLUDE_DIRS);
24406f32e7eSjoerg   if (CIncludeDirs != "") {
24506f32e7eSjoerg     SmallVector<StringRef, 5> dirs;
24606f32e7eSjoerg     CIncludeDirs.split(dirs, ":");
24706f32e7eSjoerg     for (StringRef dir : dirs) {
24806f32e7eSjoerg       StringRef Prefix =
249*13fbcb42Sjoerg           llvm::sys::path::is_absolute(dir) ? "" : StringRef(D.SysRoot);
25006f32e7eSjoerg       addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
25106f32e7eSjoerg     }
25206f32e7eSjoerg     return;
25306f32e7eSjoerg   }
25406f32e7eSjoerg 
25506f32e7eSjoerg   // Add include directories specific to the selected multilib set and multilib.
25606f32e7eSjoerg   if (GCCInstallation.isValid()) {
25706f32e7eSjoerg     const MultilibSet::IncludeDirsFunc &Callback =
25806f32e7eSjoerg         Multilibs.includeDirsCallback();
25906f32e7eSjoerg     if (Callback) {
26006f32e7eSjoerg       for (const auto &Path : Callback(GCCInstallation.getMultilib()))
26106f32e7eSjoerg         addExternCSystemIncludeIfExists(
26206f32e7eSjoerg             DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path);
26306f32e7eSjoerg     }
26406f32e7eSjoerg   }
26506f32e7eSjoerg 
26606f32e7eSjoerg   addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include");
26706f32e7eSjoerg }
26806f32e7eSjoerg 
addLibStdCxxIncludePaths(const llvm::opt::ArgList & DriverArgs,llvm::opt::ArgStringList & CC1Args) const26906f32e7eSjoerg void Solaris::addLibStdCxxIncludePaths(
27006f32e7eSjoerg     const llvm::opt::ArgList &DriverArgs,
27106f32e7eSjoerg     llvm::opt::ArgStringList &CC1Args) const {
27206f32e7eSjoerg   // We need a detected GCC installation on Solaris (similar to Linux)
27306f32e7eSjoerg   // to provide libstdc++'s headers.
27406f32e7eSjoerg   if (!GCCInstallation.isValid())
27506f32e7eSjoerg     return;
27606f32e7eSjoerg 
27706f32e7eSjoerg   // By default, look for the C++ headers in an include directory adjacent to
27806f32e7eSjoerg   // the lib directory of the GCC installation.
27906f32e7eSjoerg   // On Solaris this usually looks like /usr/gcc/X.Y/include/c++/X.Y.Z
28006f32e7eSjoerg   StringRef LibDir = GCCInstallation.getParentLibPath();
28106f32e7eSjoerg   StringRef TripleStr = GCCInstallation.getTriple().str();
28206f32e7eSjoerg   const Multilib &Multilib = GCCInstallation.getMultilib();
28306f32e7eSjoerg   const GCCVersion &Version = GCCInstallation.getVersion();
28406f32e7eSjoerg 
28506f32e7eSjoerg   // The primary search for libstdc++ supports multiarch variants.
286*13fbcb42Sjoerg   addLibStdCXXIncludePaths(LibDir.str() + "/../include/c++/" + Version.Text,
287*13fbcb42Sjoerg                            TripleStr, Multilib.includeSuffix(), DriverArgs,
288*13fbcb42Sjoerg                            CC1Args);
28906f32e7eSjoerg }
290