1 //===--- Fuchsia.cpp - Fuchsia ToolChain Implementations --------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 #include "CommonArgs.h"
11 #include "clang/Config/config.h"
12 #include "clang/Driver/Compilation.h"
13 #include "clang/Driver/Driver.h"
14 #include "clang/Driver/DriverDiagnostic.h"
15 #include "clang/Driver/MultilibBuilder.h"
16 #include "clang/Driver/Options.h"
17 #include "clang/Driver/SanitizerArgs.h"
18 #include "llvm/Option/ArgList.h"
19 #include "llvm/ProfileData/InstrProf.h"
20 #include "llvm/Support/FileSystem.h"
21 #include "llvm/Support/Path.h"
22 #include "llvm/Support/VirtualFileSystem.h"
24 using namespace clang::driver
;
25 using namespace clang::driver::toolchains
;
26 using namespace clang::driver::tools
;
27 using namespace clang
;
28 using namespace llvm::opt
;
30 using tools::addMultilibFlag
;
32 void fuchsia::Linker::ConstructJob(Compilation
&C
, const JobAction
&JA
,
33 const InputInfo
&Output
,
34 const InputInfoList
&Inputs
,
36 const char *LinkingOutput
) const {
37 const auto &ToolChain
= static_cast<const Fuchsia
&>(getToolChain());
38 const Driver
&D
= ToolChain
.getDriver();
40 const llvm::Triple
&Triple
= ToolChain
.getEffectiveTriple();
42 ArgStringList CmdArgs
;
44 // Silence warning for "clang -g foo.o -o foo"
45 Args
.ClaimAllArgs(options::OPT_g_Group
);
46 // and "clang -emit-llvm foo.o -o foo"
47 Args
.ClaimAllArgs(options::OPT_emit_llvm
);
48 // and for "clang -w foo.o -o foo". Other warning options are already
49 // handled somewhere else.
50 Args
.ClaimAllArgs(options::OPT_w
);
52 CmdArgs
.push_back("-z");
53 CmdArgs
.push_back("max-page-size=4096");
55 CmdArgs
.push_back("-z");
56 CmdArgs
.push_back("now");
58 CmdArgs
.push_back("-z");
59 CmdArgs
.push_back("start-stop-visibility=hidden");
61 const char *Exec
= Args
.MakeArgString(ToolChain
.GetLinkerPath());
62 if (llvm::sys::path::filename(Exec
).equals_insensitive("ld.lld") ||
63 llvm::sys::path::stem(Exec
).equals_insensitive("ld.lld")) {
64 CmdArgs
.push_back("-z");
65 CmdArgs
.push_back("rodynamic");
66 CmdArgs
.push_back("-z");
67 CmdArgs
.push_back("separate-loadable-segments");
68 CmdArgs
.push_back("-z");
69 CmdArgs
.push_back("rel");
70 CmdArgs
.push_back("--pack-dyn-relocs=relr");
73 if (!D
.SysRoot
.empty())
74 CmdArgs
.push_back(Args
.MakeArgString("--sysroot=" + D
.SysRoot
));
76 if (!Args
.hasArg(options::OPT_shared
) && !Args
.hasArg(options::OPT_r
))
77 CmdArgs
.push_back("-pie");
79 if (Args
.hasArg(options::OPT_rdynamic
))
80 CmdArgs
.push_back("-export-dynamic");
82 if (Args
.hasArg(options::OPT_s
))
83 CmdArgs
.push_back("-s");
85 if (Args
.hasArg(options::OPT_r
)) {
86 CmdArgs
.push_back("-r");
88 CmdArgs
.push_back("--build-id");
89 CmdArgs
.push_back("--hash-style=gnu");
92 if (ToolChain
.getArch() == llvm::Triple::aarch64
) {
93 CmdArgs
.push_back("--execute-only");
95 std::string CPU
= getCPUName(D
, Args
, Triple
);
96 if (CPU
.empty() || CPU
== "generic" || CPU
== "cortex-a53")
97 CmdArgs
.push_back("--fix-cortex-a53-843419");
100 CmdArgs
.push_back("--eh-frame-hdr");
102 if (Args
.hasArg(options::OPT_static
))
103 CmdArgs
.push_back("-Bstatic");
104 else if (Args
.hasArg(options::OPT_shared
))
105 CmdArgs
.push_back("-shared");
107 const SanitizerArgs
&SanArgs
= ToolChain
.getSanitizerArgs(Args
);
109 if (!Args
.hasArg(options::OPT_shared
) && !Args
.hasArg(options::OPT_r
)) {
110 std::string Dyld
= D
.DyldPrefix
;
111 if (SanArgs
.needsAsanRt() && SanArgs
.needsSharedRt())
113 if (SanArgs
.needsHwasanRt() && SanArgs
.needsSharedRt())
115 if (SanArgs
.needsTsanRt() && SanArgs
.needsSharedRt())
118 CmdArgs
.push_back("-dynamic-linker");
119 CmdArgs
.push_back(Args
.MakeArgString(Dyld
));
122 if (ToolChain
.getArch() == llvm::Triple::riscv64
)
123 CmdArgs
.push_back("-X");
125 CmdArgs
.push_back("-o");
126 CmdArgs
.push_back(Output
.getFilename());
128 if (!Args
.hasArg(options::OPT_nostdlib
, options::OPT_nostartfiles
,
130 if (!Args
.hasArg(options::OPT_shared
)) {
131 CmdArgs
.push_back(Args
.MakeArgString(ToolChain
.GetFilePath("Scrt1.o")));
135 Args
.addAllArgs(CmdArgs
, {options::OPT_L
, options::OPT_u
});
137 ToolChain
.AddFilePathLibArgs(Args
, CmdArgs
);
139 if (D
.isUsingLTO()) {
140 assert(!Inputs
.empty() && "Must have at least one input.");
141 // Find the first filename InputInfo object.
142 auto Input
= llvm::find_if(
143 Inputs
, [](const InputInfo
&II
) -> bool { return II
.isFilename(); });
144 if (Input
== Inputs
.end())
145 // For a very rare case, all of the inputs to the linker are
146 // InputArg. If that happens, just use the first InputInfo.
147 Input
= Inputs
.begin();
149 addLTOOptions(ToolChain
, Args
, CmdArgs
, Output
, *Input
,
150 D
.getLTOMode() == LTOK_Thin
);
153 addLinkerCompressDebugSectionsOption(ToolChain
, Args
, CmdArgs
);
154 AddLinkerInputs(ToolChain
, Inputs
, Args
, CmdArgs
, JA
);
156 if (!Args
.hasArg(options::OPT_nostdlib
, options::OPT_nodefaultlibs
,
158 if (Args
.hasArg(options::OPT_static
))
159 CmdArgs
.push_back("-Bdynamic");
162 if (ToolChain
.ShouldLinkCXXStdlib(Args
)) {
163 bool OnlyLibstdcxxStatic
= Args
.hasArg(options::OPT_static_libstdcxx
) &&
164 !Args
.hasArg(options::OPT_static
);
165 CmdArgs
.push_back("--push-state");
166 CmdArgs
.push_back("--as-needed");
167 if (OnlyLibstdcxxStatic
)
168 CmdArgs
.push_back("-Bstatic");
169 ToolChain
.AddCXXStdlibLibArgs(Args
, CmdArgs
);
170 if (OnlyLibstdcxxStatic
)
171 CmdArgs
.push_back("-Bdynamic");
172 CmdArgs
.push_back("-lm");
173 CmdArgs
.push_back("--pop-state");
177 // Note that Fuchsia never needs to link in sanitizer runtime deps. Any
178 // sanitizer runtimes with system dependencies use the `.deplibs` feature
180 addSanitizerRuntimes(ToolChain
, Args
, CmdArgs
);
182 addXRayRuntime(ToolChain
, Args
, CmdArgs
);
184 ToolChain
.addProfileRTLibs(Args
, CmdArgs
);
186 AddRunTimeLibs(ToolChain
, D
, CmdArgs
, Args
);
188 if (Args
.hasArg(options::OPT_pthread
) ||
189 Args
.hasArg(options::OPT_pthreads
))
190 CmdArgs
.push_back("-lpthread");
192 if (Args
.hasArg(options::OPT_fsplit_stack
))
193 CmdArgs
.push_back("--wrap=pthread_create");
195 if (!Args
.hasArg(options::OPT_nolibc
))
196 CmdArgs
.push_back("-lc");
199 C
.addCommand(std::make_unique
<Command
>(JA
, *this,
200 ResponseFileSupport::AtFileCurCP(),
201 Exec
, CmdArgs
, Inputs
, Output
));
204 void fuchsia::StaticLibTool::ConstructJob(Compilation
&C
, const JobAction
&JA
,
205 const InputInfo
&Output
,
206 const InputInfoList
&Inputs
,
208 const char *LinkingOutput
) const {
209 const Driver
&D
= getToolChain().getDriver();
211 // Silence warning for "clang -g foo.o -o foo"
212 Args
.ClaimAllArgs(options::OPT_g_Group
);
213 // and "clang -emit-llvm foo.o -o foo"
214 Args
.ClaimAllArgs(options::OPT_emit_llvm
);
215 // and for "clang -w foo.o -o foo". Other warning options are already
216 // handled somewhere else.
217 Args
.ClaimAllArgs(options::OPT_w
);
218 // Silence warnings when linking C code with a C++ '-stdlib' argument.
219 Args
.ClaimAllArgs(options::OPT_stdlib_EQ
);
221 // ar tool command "llvm-ar <options> <output_file> <input_files>".
222 ArgStringList CmdArgs
;
223 // Create and insert file members with a deterministic index.
224 CmdArgs
.push_back("rcsD");
225 CmdArgs
.push_back(Output
.getFilename());
227 for (const auto &II
: Inputs
) {
228 if (II
.isFilename()) {
229 CmdArgs
.push_back(II
.getFilename());
233 // Delete old output archive file if it already exists before generating a new
235 const char *OutputFileName
= Output
.getFilename();
236 if (Output
.isFilename() && llvm::sys::fs::exists(OutputFileName
)) {
237 if (std::error_code EC
= llvm::sys::fs::remove(OutputFileName
)) {
238 D
.Diag(diag::err_drv_unable_to_remove_file
) << EC
.message();
243 const char *Exec
= Args
.MakeArgString(getToolChain().GetStaticLibToolPath());
244 C
.addCommand(std::make_unique
<Command
>(JA
, *this,
245 ResponseFileSupport::AtFileCurCP(),
246 Exec
, CmdArgs
, Inputs
, Output
));
249 /// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly.
251 Fuchsia::Fuchsia(const Driver
&D
, const llvm::Triple
&Triple
,
253 : ToolChain(D
, Triple
, Args
) {
254 getProgramPaths().push_back(getDriver().getInstalledDir());
255 if (getDriver().getInstalledDir() != D
.Dir
)
256 getProgramPaths().push_back(D
.Dir
);
258 if (!D
.SysRoot
.empty()) {
259 SmallString
<128> P(D
.SysRoot
);
260 llvm::sys::path::append(P
, "lib");
261 getFilePaths().push_back(std::string(P
.str()));
264 auto FilePaths
= [&](const Multilib
&M
) -> std::vector
<std::string
> {
265 std::vector
<std::string
> FP
;
266 if (std::optional
<std::string
> Path
= getStdlibPath()) {
267 SmallString
<128> P(*Path
);
268 llvm::sys::path::append(P
, M
.gccSuffix());
269 FP
.push_back(std::string(P
.str()));
274 Multilibs
.push_back(Multilib());
275 // Use the noexcept variant with -fno-exceptions to avoid the extra overhead.
276 Multilibs
.push_back(MultilibBuilder("noexcept", {}, {})
277 .flag("-fexceptions", /*Disallow=*/true)
278 .flag("-fno-exceptions")
280 // ASan has higher priority because we always want the instrumentated version.
281 Multilibs
.push_back(MultilibBuilder("asan", {}, {})
282 .flag("-fsanitize=address")
284 // Use the asan+noexcept variant with ASan and -fno-exceptions.
285 Multilibs
.push_back(MultilibBuilder("asan+noexcept", {}, {})
286 .flag("-fsanitize=address")
287 .flag("-fexceptions", /*Disallow=*/true)
288 .flag("-fno-exceptions")
290 // HWASan has higher priority because we always want the instrumentated
292 Multilibs
.push_back(MultilibBuilder("hwasan", {}, {})
293 .flag("-fsanitize=hwaddress")
295 // Use the hwasan+noexcept variant with HWASan and -fno-exceptions.
296 Multilibs
.push_back(MultilibBuilder("hwasan+noexcept", {}, {})
297 .flag("-fsanitize=hwaddress")
298 .flag("-fexceptions", /*Disallow=*/true)
299 .flag("-fno-exceptions")
301 // Use Itanium C++ ABI for the compat multilib.
302 Multilibs
.push_back(MultilibBuilder("compat", {}, {})
303 .flag("-fc++-abi=itanium")
306 Multilibs
.FilterOut([&](const Multilib
&M
) {
307 std::vector
<std::string
> RD
= FilePaths(M
);
308 return llvm::all_of(RD
, [&](std::string P
) { return !getVFS().exists(P
); });
311 Multilib::flags_list Flags
;
313 Args
.hasFlag(options::OPT_fexceptions
, options::OPT_fno_exceptions
, true);
314 addMultilibFlag(Exceptions
, "-fexceptions", Flags
);
315 addMultilibFlag(!Exceptions
, "-fno-exceptions", Flags
);
316 addMultilibFlag(getSanitizerArgs(Args
).needsAsanRt(), "-fsanitize=address",
318 addMultilibFlag(getSanitizerArgs(Args
).needsHwasanRt(),
319 "-fsanitize=hwaddress", Flags
);
321 addMultilibFlag(Args
.getLastArgValue(options::OPT_fcxx_abi_EQ
) == "itanium",
322 "-fc++-abi=itanium", Flags
);
324 Multilibs
.setFilePathsCallback(FilePaths
);
326 if (Multilibs
.select(Flags
, SelectedMultilibs
)) {
327 // Ensure that -print-multi-directory only outputs one multilib directory.
328 Multilib LastSelected
= SelectedMultilibs
.back();
329 SelectedMultilibs
= {LastSelected
};
331 if (!SelectedMultilibs
.back().isDefault())
332 if (const auto &PathsCallback
= Multilibs
.filePathsCallback())
333 for (const auto &Path
: PathsCallback(SelectedMultilibs
.back()))
334 // Prepend the multilib path to ensure it takes the precedence.
335 getFilePaths().insert(getFilePaths().begin(), Path
);
339 std::string
Fuchsia::ComputeEffectiveClangTriple(const ArgList
&Args
,
340 types::ID InputType
) const {
341 llvm::Triple
Triple(ComputeLLVMTriple(Args
, InputType
));
345 Tool
*Fuchsia::buildLinker() const {
346 return new tools::fuchsia::Linker(*this);
349 Tool
*Fuchsia::buildStaticLibTool() const {
350 return new tools::fuchsia::StaticLibTool(*this);
353 ToolChain::RuntimeLibType
Fuchsia::GetRuntimeLibType(
354 const ArgList
&Args
) const {
355 if (Arg
*A
= Args
.getLastArg(clang::driver::options::OPT_rtlib_EQ
)) {
356 StringRef Value
= A
->getValue();
357 if (Value
!= "compiler-rt")
358 getDriver().Diag(clang::diag::err_drv_invalid_rtlib_name
)
359 << A
->getAsString(Args
);
362 return ToolChain::RLT_CompilerRT
;
365 ToolChain::CXXStdlibType
366 Fuchsia::GetCXXStdlibType(const ArgList
&Args
) const {
367 if (Arg
*A
= Args
.getLastArg(options::OPT_stdlib_EQ
)) {
368 StringRef Value
= A
->getValue();
369 if (Value
!= "libc++")
370 getDriver().Diag(diag::err_drv_invalid_stdlib_name
)
371 << A
->getAsString(Args
);
374 return ToolChain::CST_Libcxx
;
377 void Fuchsia::addClangTargetOptions(const ArgList
&DriverArgs
,
378 ArgStringList
&CC1Args
,
379 Action::OffloadKind
) const {
380 if (!DriverArgs
.hasFlag(options::OPT_fuse_init_array
,
381 options::OPT_fno_use_init_array
, true))
382 CC1Args
.push_back("-fno-use-init-array");
385 void Fuchsia::AddClangSystemIncludeArgs(const ArgList
&DriverArgs
,
386 ArgStringList
&CC1Args
) const {
387 const Driver
&D
= getDriver();
389 if (DriverArgs
.hasArg(options::OPT_nostdinc
))
392 if (!DriverArgs
.hasArg(options::OPT_nobuiltininc
)) {
393 SmallString
<128> P(D
.ResourceDir
);
394 llvm::sys::path::append(P
, "include");
395 addSystemInclude(DriverArgs
, CC1Args
, P
);
398 if (DriverArgs
.hasArg(options::OPT_nostdlibinc
))
401 // Check for configure-time C include directories.
402 StringRef
CIncludeDirs(C_INCLUDE_DIRS
);
403 if (CIncludeDirs
!= "") {
404 SmallVector
<StringRef
, 5> dirs
;
405 CIncludeDirs
.split(dirs
, ":");
406 for (StringRef dir
: dirs
) {
408 llvm::sys::path::is_absolute(dir
) ? "" : StringRef(D
.SysRoot
);
409 addExternCSystemInclude(DriverArgs
, CC1Args
, Prefix
+ dir
);
414 if (!D
.SysRoot
.empty()) {
415 SmallString
<128> P(D
.SysRoot
);
416 llvm::sys::path::append(P
, "include");
417 addExternCSystemInclude(DriverArgs
, CC1Args
, P
.str());
421 void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList
&DriverArgs
,
422 ArgStringList
&CC1Args
) const {
423 if (DriverArgs
.hasArg(options::OPT_nostdinc
, options::OPT_nostdlibinc
,
424 options::OPT_nostdincxx
))
427 const Driver
&D
= getDriver();
428 std::string Target
= getTripleString();
430 auto AddCXXIncludePath
= [&](StringRef Path
) {
431 std::string Version
= detectLibcxxVersion(Path
);
435 // First add the per-target include path.
436 SmallString
<128> TargetDir(Path
);
437 llvm::sys::path::append(TargetDir
, Target
, "c++", Version
);
438 if (getVFS().exists(TargetDir
))
439 addSystemInclude(DriverArgs
, CC1Args
, TargetDir
);
441 // Second add the generic one.
442 SmallString
<128> Dir(Path
);
443 llvm::sys::path::append(Dir
, "c++", Version
);
444 addSystemInclude(DriverArgs
, CC1Args
, Dir
);
447 switch (GetCXXStdlibType(DriverArgs
)) {
448 case ToolChain::CST_Libcxx
: {
449 SmallString
<128> P(D
.Dir
);
450 llvm::sys::path::append(P
, "..", "include");
451 AddCXXIncludePath(P
);
456 llvm_unreachable("invalid stdlib name");
460 void Fuchsia::AddCXXStdlibLibArgs(const ArgList
&Args
,
461 ArgStringList
&CmdArgs
) const {
462 switch (GetCXXStdlibType(Args
)) {
463 case ToolChain::CST_Libcxx
:
464 CmdArgs
.push_back("-lc++");
465 if (Args
.hasArg(options::OPT_fexperimental_library
))
466 CmdArgs
.push_back("-lc++experimental");
469 case ToolChain::CST_Libstdcxx
:
470 llvm_unreachable("invalid stdlib name");
474 SanitizerMask
Fuchsia::getSupportedSanitizers() const {
475 SanitizerMask Res
= ToolChain::getSupportedSanitizers();
476 Res
|= SanitizerKind::Address
;
477 Res
|= SanitizerKind::HWAddress
;
478 Res
|= SanitizerKind::PointerCompare
;
479 Res
|= SanitizerKind::PointerSubtract
;
480 Res
|= SanitizerKind::Fuzzer
;
481 Res
|= SanitizerKind::FuzzerNoLink
;
482 Res
|= SanitizerKind::Leak
;
483 Res
|= SanitizerKind::SafeStack
;
484 Res
|= SanitizerKind::Scudo
;
485 Res
|= SanitizerKind::Thread
;
489 SanitizerMask
Fuchsia::getDefaultSanitizers() const {
491 switch (getTriple().getArch()) {
492 case llvm::Triple::aarch64
:
493 case llvm::Triple::riscv64
:
494 Res
|= SanitizerKind::ShadowCallStack
;
496 case llvm::Triple::x86_64
:
497 Res
|= SanitizerKind::SafeStack
;