1e5dd7070Spatrick //===--- Solaris.cpp - Solaris ToolChain Implementations --------*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick
9e5dd7070Spatrick #include "Solaris.h"
10e5dd7070Spatrick #include "CommonArgs.h"
11e5dd7070Spatrick #include "clang/Basic/LangStandard.h"
12e5dd7070Spatrick #include "clang/Config/config.h"
13e5dd7070Spatrick #include "clang/Driver/Compilation.h"
14e5dd7070Spatrick #include "clang/Driver/Driver.h"
15e5dd7070Spatrick #include "clang/Driver/DriverDiagnostic.h"
16e5dd7070Spatrick #include "clang/Driver/Options.h"
17*12c85518Srobert #include "clang/Driver/SanitizerArgs.h"
18*12c85518Srobert #include "clang/Driver/ToolChain.h"
19e5dd7070Spatrick #include "llvm/Option/ArgList.h"
20e5dd7070Spatrick #include "llvm/Support/FileSystem.h"
21e5dd7070Spatrick #include "llvm/Support/Path.h"
22e5dd7070Spatrick
23e5dd7070Spatrick using namespace clang::driver;
24e5dd7070Spatrick using namespace clang::driver::tools;
25e5dd7070Spatrick using namespace clang::driver::toolchains;
26e5dd7070Spatrick using namespace clang;
27e5dd7070Spatrick using namespace llvm::opt;
28e5dd7070Spatrick
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const29e5dd7070Spatrick void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
30e5dd7070Spatrick const InputInfo &Output,
31e5dd7070Spatrick const InputInfoList &Inputs,
32e5dd7070Spatrick const ArgList &Args,
33e5dd7070Spatrick const char *LinkingOutput) const {
34e5dd7070Spatrick claimNoWarnArgs(Args);
35e5dd7070Spatrick ArgStringList CmdArgs;
36e5dd7070Spatrick
37e5dd7070Spatrick Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
38e5dd7070Spatrick
39e5dd7070Spatrick CmdArgs.push_back("-o");
40e5dd7070Spatrick CmdArgs.push_back(Output.getFilename());
41e5dd7070Spatrick
42e5dd7070Spatrick for (const auto &II : Inputs)
43e5dd7070Spatrick CmdArgs.push_back(II.getFilename());
44e5dd7070Spatrick
45e5dd7070Spatrick const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
46ec727ea7Spatrick C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
47a9ac8606Spatrick Exec, CmdArgs, Inputs, Output));
48e5dd7070Spatrick }
49e5dd7070Spatrick
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const50e5dd7070Spatrick void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
51e5dd7070Spatrick const InputInfo &Output,
52e5dd7070Spatrick const InputInfoList &Inputs,
53e5dd7070Spatrick const ArgList &Args,
54e5dd7070Spatrick const char *LinkingOutput) const {
55e5dd7070Spatrick ArgStringList CmdArgs;
56e5dd7070Spatrick
57e5dd7070Spatrick // Demangle C++ names in errors
58e5dd7070Spatrick CmdArgs.push_back("-C");
59e5dd7070Spatrick
60e5dd7070Spatrick if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
61e5dd7070Spatrick CmdArgs.push_back("-e");
62e5dd7070Spatrick CmdArgs.push_back("_start");
63e5dd7070Spatrick }
64e5dd7070Spatrick
65e5dd7070Spatrick if (Args.hasArg(options::OPT_static)) {
66e5dd7070Spatrick CmdArgs.push_back("-Bstatic");
67e5dd7070Spatrick CmdArgs.push_back("-dn");
68e5dd7070Spatrick } else {
69e5dd7070Spatrick CmdArgs.push_back("-Bdynamic");
70e5dd7070Spatrick if (Args.hasArg(options::OPT_shared)) {
71e5dd7070Spatrick CmdArgs.push_back("-shared");
72e5dd7070Spatrick }
73e5dd7070Spatrick
74e5dd7070Spatrick // libpthread has been folded into libc since Solaris 10, no need to do
75e5dd7070Spatrick // anything for pthreads. Claim argument to avoid warning.
76e5dd7070Spatrick Args.ClaimAllArgs(options::OPT_pthread);
77e5dd7070Spatrick Args.ClaimAllArgs(options::OPT_pthreads);
78e5dd7070Spatrick }
79e5dd7070Spatrick
80e5dd7070Spatrick if (Output.isFilename()) {
81e5dd7070Spatrick CmdArgs.push_back("-o");
82e5dd7070Spatrick CmdArgs.push_back(Output.getFilename());
83e5dd7070Spatrick } else {
84e5dd7070Spatrick assert(Output.isNothing() && "Invalid output.");
85e5dd7070Spatrick }
86e5dd7070Spatrick
87*12c85518Srobert if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
88*12c85518Srobert options::OPT_r)) {
89e5dd7070Spatrick if (!Args.hasArg(options::OPT_shared))
90e5dd7070Spatrick CmdArgs.push_back(
91e5dd7070Spatrick Args.MakeArgString(getToolChain().GetFilePath("crt1.o")));
92e5dd7070Spatrick
93e5dd7070Spatrick CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
94e5dd7070Spatrick
95e5dd7070Spatrick const Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi);
96e5dd7070Spatrick bool HaveAnsi = false;
97e5dd7070Spatrick const LangStandard *LangStd = nullptr;
98e5dd7070Spatrick if (Std) {
99e5dd7070Spatrick HaveAnsi = Std->getOption().matches(options::OPT_ansi);
100e5dd7070Spatrick if (!HaveAnsi)
101e5dd7070Spatrick LangStd = LangStandard::getLangStandardForName(Std->getValue());
102e5dd7070Spatrick }
103e5dd7070Spatrick
104e5dd7070Spatrick const char *values_X = "values-Xa.o";
105e5dd7070Spatrick // Use values-Xc.o for -ansi, -std=c*, -std=iso9899:199409.
106e5dd7070Spatrick if (HaveAnsi || (LangStd && !LangStd->isGNUMode()))
107e5dd7070Spatrick values_X = "values-Xc.o";
108e5dd7070Spatrick CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(values_X)));
109e5dd7070Spatrick
110e5dd7070Spatrick const char *values_xpg = "values-xpg6.o";
111e5dd7070Spatrick // Use values-xpg4.o for -std=c90, -std=gnu90, -std=iso9899:199409.
112e5dd7070Spatrick if (LangStd && LangStd->getLanguage() == Language::C && !LangStd->isC99())
113e5dd7070Spatrick values_xpg = "values-xpg4.o";
114e5dd7070Spatrick CmdArgs.push_back(
115e5dd7070Spatrick Args.MakeArgString(getToolChain().GetFilePath(values_xpg)));
116e5dd7070Spatrick CmdArgs.push_back(
117e5dd7070Spatrick Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
118*12c85518Srobert // Add crtfastmath.o if available and fast math is enabled.
119*12c85518Srobert getToolChain().addFastMathRuntimeIfAvailable(Args, CmdArgs);
120e5dd7070Spatrick }
121e5dd7070Spatrick
122e5dd7070Spatrick getToolChain().AddFilePathLibArgs(Args, CmdArgs);
123e5dd7070Spatrick
124e5dd7070Spatrick Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
125e5dd7070Spatrick options::OPT_e, options::OPT_r});
126e5dd7070Spatrick
127e5dd7070Spatrick bool NeedsSanitizerDeps = addSanitizerRuntimes(getToolChain(), Args, CmdArgs);
128e5dd7070Spatrick AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
129e5dd7070Spatrick
130*12c85518Srobert if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
131*12c85518Srobert options::OPT_r)) {
132e5dd7070Spatrick if (getToolChain().ShouldLinkCXXStdlib(Args))
133e5dd7070Spatrick getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
134e5dd7070Spatrick if (Args.hasArg(options::OPT_fstack_protector) ||
135e5dd7070Spatrick Args.hasArg(options::OPT_fstack_protector_strong) ||
136e5dd7070Spatrick Args.hasArg(options::OPT_fstack_protector_all)) {
137e5dd7070Spatrick // Explicitly link ssp libraries, not folded into Solaris libc.
138e5dd7070Spatrick CmdArgs.push_back("-lssp_nonshared");
139e5dd7070Spatrick CmdArgs.push_back("-lssp");
140e5dd7070Spatrick }
141*12c85518Srobert // LLVM support for atomics on 32-bit SPARC V8+ is incomplete, so
142*12c85518Srobert // forcibly link with libatomic as a workaround.
143*12c85518Srobert if (getToolChain().getTriple().getArch() == llvm::Triple::sparc) {
144*12c85518Srobert CmdArgs.push_back(getAsNeededOption(getToolChain(), true));
145*12c85518Srobert CmdArgs.push_back("-latomic");
146*12c85518Srobert CmdArgs.push_back(getAsNeededOption(getToolChain(), false));
147*12c85518Srobert }
148e5dd7070Spatrick CmdArgs.push_back("-lgcc_s");
149e5dd7070Spatrick CmdArgs.push_back("-lc");
150e5dd7070Spatrick if (!Args.hasArg(options::OPT_shared)) {
151e5dd7070Spatrick CmdArgs.push_back("-lgcc");
152e5dd7070Spatrick CmdArgs.push_back("-lm");
153e5dd7070Spatrick }
154*12c85518Srobert if (NeedsSanitizerDeps) {
155e5dd7070Spatrick linkSanitizerRuntimeDeps(getToolChain(), CmdArgs);
156*12c85518Srobert
157*12c85518Srobert // Work around Solaris/amd64 ld bug when calling __tls_get_addr directly.
158*12c85518Srobert // However, ld -z relax=transtls is available since Solaris 11.2, but not
159*12c85518Srobert // in Illumos.
160*12c85518Srobert const SanitizerArgs &SA = getToolChain().getSanitizerArgs(Args);
161*12c85518Srobert if (getToolChain().getTriple().getArch() == llvm::Triple::x86_64 &&
162*12c85518Srobert (SA.needsAsanRt() || SA.needsStatsRt() ||
163*12c85518Srobert (SA.needsUbsanRt() && !SA.requiresMinimalRuntime())))
164*12c85518Srobert CmdArgs.push_back("-zrelax=transtls");
165*12c85518Srobert }
166e5dd7070Spatrick }
167e5dd7070Spatrick
168*12c85518Srobert if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
169*12c85518Srobert options::OPT_r)) {
170e5dd7070Spatrick CmdArgs.push_back(
171e5dd7070Spatrick Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
172*12c85518Srobert CmdArgs.push_back(
173*12c85518Srobert Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
174e5dd7070Spatrick }
175e5dd7070Spatrick
176e5dd7070Spatrick getToolChain().addProfileRTLibs(Args, CmdArgs);
177e5dd7070Spatrick
178e5dd7070Spatrick const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
179ec727ea7Spatrick C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
180a9ac8606Spatrick Exec, CmdArgs, Inputs, Output));
181e5dd7070Spatrick }
182e5dd7070Spatrick
getSolarisLibSuffix(const llvm::Triple & Triple)183e5dd7070Spatrick static StringRef getSolarisLibSuffix(const llvm::Triple &Triple) {
184e5dd7070Spatrick switch (Triple.getArch()) {
185e5dd7070Spatrick case llvm::Triple::x86:
186e5dd7070Spatrick case llvm::Triple::sparc:
187e5dd7070Spatrick break;
188e5dd7070Spatrick case llvm::Triple::x86_64:
189e5dd7070Spatrick return "/amd64";
190e5dd7070Spatrick case llvm::Triple::sparcv9:
191e5dd7070Spatrick return "/sparcv9";
192e5dd7070Spatrick default:
193e5dd7070Spatrick llvm_unreachable("Unsupported architecture");
194e5dd7070Spatrick }
195e5dd7070Spatrick return "";
196e5dd7070Spatrick }
197e5dd7070Spatrick
198e5dd7070Spatrick /// Solaris - Solaris tool chain which can call as(1) and ld(1) directly.
199e5dd7070Spatrick
Solaris(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)200e5dd7070Spatrick Solaris::Solaris(const Driver &D, const llvm::Triple &Triple,
201e5dd7070Spatrick const ArgList &Args)
202e5dd7070Spatrick : Generic_ELF(D, Triple, Args) {
203e5dd7070Spatrick
204e5dd7070Spatrick GCCInstallation.init(Triple, Args);
205e5dd7070Spatrick
206e5dd7070Spatrick StringRef LibSuffix = getSolarisLibSuffix(Triple);
207e5dd7070Spatrick path_list &Paths = getFilePaths();
208e5dd7070Spatrick if (GCCInstallation.isValid()) {
209e5dd7070Spatrick // On Solaris gcc uses both an architecture-specific path with triple in it
210e5dd7070Spatrick // as well as a more generic lib path (+arch suffix).
211e5dd7070Spatrick addPathIfExists(D,
212e5dd7070Spatrick GCCInstallation.getInstallPath() +
213e5dd7070Spatrick GCCInstallation.getMultilib().gccSuffix(),
214e5dd7070Spatrick Paths);
215e5dd7070Spatrick addPathIfExists(D, GCCInstallation.getParentLibPath() + LibSuffix, Paths);
216e5dd7070Spatrick }
217e5dd7070Spatrick
218e5dd7070Spatrick // If we are currently running Clang inside of the requested system root,
219e5dd7070Spatrick // add its parent library path to those searched.
220e5dd7070Spatrick if (StringRef(D.Dir).startswith(D.SysRoot))
221e5dd7070Spatrick addPathIfExists(D, D.Dir + "/../lib", Paths);
222e5dd7070Spatrick
223e5dd7070Spatrick addPathIfExists(D, D.SysRoot + "/usr/lib" + LibSuffix, Paths);
224e5dd7070Spatrick }
225e5dd7070Spatrick
getSupportedSanitizers() const226e5dd7070Spatrick SanitizerMask Solaris::getSupportedSanitizers() const {
227e5dd7070Spatrick const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
228e5dd7070Spatrick const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
229e5dd7070Spatrick SanitizerMask Res = ToolChain::getSupportedSanitizers();
230e5dd7070Spatrick // FIXME: Omit X86_64 until 64-bit support is figured out.
231e5dd7070Spatrick if (IsX86) {
232e5dd7070Spatrick Res |= SanitizerKind::Address;
233e5dd7070Spatrick Res |= SanitizerKind::PointerCompare;
234e5dd7070Spatrick Res |= SanitizerKind::PointerSubtract;
235e5dd7070Spatrick }
236e5dd7070Spatrick if (IsX86 || IsX86_64)
237e5dd7070Spatrick Res |= SanitizerKind::Function;
238e5dd7070Spatrick Res |= SanitizerKind::Vptr;
239e5dd7070Spatrick return Res;
240e5dd7070Spatrick }
241e5dd7070Spatrick
buildAssembler() const242e5dd7070Spatrick Tool *Solaris::buildAssembler() const {
243e5dd7070Spatrick return new tools::solaris::Assembler(*this);
244e5dd7070Spatrick }
245e5dd7070Spatrick
buildLinker() const246e5dd7070Spatrick Tool *Solaris::buildLinker() const { return new tools::solaris::Linker(*this); }
247e5dd7070Spatrick
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const248e5dd7070Spatrick void Solaris::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
249e5dd7070Spatrick ArgStringList &CC1Args) const {
250e5dd7070Spatrick const Driver &D = getDriver();
251e5dd7070Spatrick
252e5dd7070Spatrick if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
253e5dd7070Spatrick return;
254e5dd7070Spatrick
255e5dd7070Spatrick if (!DriverArgs.hasArg(options::OPT_nostdlibinc))
256e5dd7070Spatrick addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/local/include");
257e5dd7070Spatrick
258e5dd7070Spatrick if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
259e5dd7070Spatrick SmallString<128> P(D.ResourceDir);
260e5dd7070Spatrick llvm::sys::path::append(P, "include");
261e5dd7070Spatrick addSystemInclude(DriverArgs, CC1Args, P);
262e5dd7070Spatrick }
263e5dd7070Spatrick
264e5dd7070Spatrick if (DriverArgs.hasArg(options::OPT_nostdlibinc))
265e5dd7070Spatrick return;
266e5dd7070Spatrick
267e5dd7070Spatrick // Check for configure-time C include directories.
268e5dd7070Spatrick StringRef CIncludeDirs(C_INCLUDE_DIRS);
269e5dd7070Spatrick if (CIncludeDirs != "") {
270e5dd7070Spatrick SmallVector<StringRef, 5> dirs;
271e5dd7070Spatrick CIncludeDirs.split(dirs, ":");
272e5dd7070Spatrick for (StringRef dir : dirs) {
273e5dd7070Spatrick StringRef Prefix =
274ec727ea7Spatrick llvm::sys::path::is_absolute(dir) ? "" : StringRef(D.SysRoot);
275e5dd7070Spatrick addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
276e5dd7070Spatrick }
277e5dd7070Spatrick return;
278e5dd7070Spatrick }
279e5dd7070Spatrick
280e5dd7070Spatrick // Add include directories specific to the selected multilib set and multilib.
281e5dd7070Spatrick if (GCCInstallation.isValid()) {
282e5dd7070Spatrick const MultilibSet::IncludeDirsFunc &Callback =
283e5dd7070Spatrick Multilibs.includeDirsCallback();
284e5dd7070Spatrick if (Callback) {
285e5dd7070Spatrick for (const auto &Path : Callback(GCCInstallation.getMultilib()))
286e5dd7070Spatrick addExternCSystemIncludeIfExists(
287e5dd7070Spatrick DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path);
288e5dd7070Spatrick }
289e5dd7070Spatrick }
290e5dd7070Spatrick
291e5dd7070Spatrick addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include");
292e5dd7070Spatrick }
293e5dd7070Spatrick
addLibStdCxxIncludePaths(const llvm::opt::ArgList & DriverArgs,llvm::opt::ArgStringList & CC1Args) const294e5dd7070Spatrick void Solaris::addLibStdCxxIncludePaths(
295e5dd7070Spatrick const llvm::opt::ArgList &DriverArgs,
296e5dd7070Spatrick llvm::opt::ArgStringList &CC1Args) const {
297e5dd7070Spatrick // We need a detected GCC installation on Solaris (similar to Linux)
298e5dd7070Spatrick // to provide libstdc++'s headers.
299e5dd7070Spatrick if (!GCCInstallation.isValid())
300e5dd7070Spatrick return;
301e5dd7070Spatrick
302e5dd7070Spatrick // By default, look for the C++ headers in an include directory adjacent to
303e5dd7070Spatrick // the lib directory of the GCC installation.
304e5dd7070Spatrick // On Solaris this usually looks like /usr/gcc/X.Y/include/c++/X.Y.Z
305e5dd7070Spatrick StringRef LibDir = GCCInstallation.getParentLibPath();
306e5dd7070Spatrick StringRef TripleStr = GCCInstallation.getTriple().str();
307e5dd7070Spatrick const Multilib &Multilib = GCCInstallation.getMultilib();
308e5dd7070Spatrick const GCCVersion &Version = GCCInstallation.getVersion();
309e5dd7070Spatrick
310e5dd7070Spatrick // The primary search for libstdc++ supports multiarch variants.
311a9ac8606Spatrick addLibStdCXXIncludePaths(LibDir.str() + "/../include/c++/" + Version.Text,
312a9ac8606Spatrick TripleStr, Multilib.includeSuffix(), DriverArgs,
313a9ac8606Spatrick CC1Args);
314e5dd7070Spatrick }
315