1 | //===--- WebAssembly.cpp - WebAssembly ToolChain Implementation -*- C++ -*-===// |
---|---|
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "WebAssembly.h" |
10 | #include "Gnu.h" |
11 | #include "clang/Config/config.h" |
12 | #include "clang/Driver/CommonArgs.h" |
13 | #include "clang/Driver/Compilation.h" |
14 | #include "clang/Driver/Driver.h" |
15 | #include "clang/Driver/Options.h" |
16 | #include "llvm/Config/llvm-config.h" // for LLVM_VERSION_STRING |
17 | #include "llvm/Option/ArgList.h" |
18 | #include "llvm/Support/FileSystem.h" |
19 | #include "llvm/Support/Path.h" |
20 | #include "llvm/Support/VirtualFileSystem.h" |
21 | |
22 | using namespace clang::driver; |
23 | using namespace clang::driver::tools; |
24 | using namespace clang::driver::toolchains; |
25 | using namespace clang; |
26 | using namespace llvm::opt; |
27 | |
28 | /// Following the conventions in https://wiki.debian.org/Multiarch/Tuples, |
29 | /// we remove the vendor field to form the multiarch triple. |
30 | std::string WebAssembly::getMultiarchTriple(const Driver &D, |
31 | const llvm::Triple &TargetTriple, |
32 | StringRef SysRoot) const { |
33 | return (TargetTriple.getArchName() + "-"+ |
34 | TargetTriple.getOSAndEnvironmentName()).str(); |
35 | } |
36 | |
37 | std::string wasm::Linker::getLinkerPath(const ArgList &Args) const { |
38 | const ToolChain &ToolChain = getToolChain(); |
39 | if (const Arg* A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { |
40 | StringRef UseLinker = A->getValue(); |
41 | if (!UseLinker.empty()) { |
42 | if (llvm::sys::path::is_absolute(path: UseLinker) && |
43 | llvm::sys::fs::can_execute(Path: UseLinker)) |
44 | return std::string(UseLinker); |
45 | |
46 | // Interpret 'lld' as explicitly requesting `wasm-ld`, so look for that |
47 | // linker. Note that for `wasm32-wasip2` this overrides the default linker |
48 | // of `wasm-component-ld`. |
49 | if (UseLinker == "lld") { |
50 | return ToolChain.GetProgramPath(Name: "wasm-ld"); |
51 | } |
52 | |
53 | // Allow 'ld' as an alias for the default linker |
54 | if (UseLinker != "ld") |
55 | ToolChain.getDriver().Diag(diag::DiagID: err_drv_invalid_linker_name) |
56 | << A->getAsString(Args); |
57 | } |
58 | } |
59 | |
60 | return ToolChain.GetProgramPath(Name: ToolChain.getDefaultLinker()); |
61 | } |
62 | |
63 | static bool TargetBuildsComponents(const llvm::Triple &TargetTriple) { |
64 | // WASIp2 and above are all based on components, so test for WASI but exclude |
65 | // the original `wasi` target in addition to the `wasip1` name. |
66 | return TargetTriple.isOSWASI() && TargetTriple.getOSName() != "wasip1"&& |
67 | TargetTriple.getOSName() != "wasi"; |
68 | } |
69 | |
70 | static bool WantsPthread(const llvm::Triple &Triple, const ArgList &Args) { |
71 | bool WantsPthread = |
72 | Args.hasFlag(options::OPT_pthread, options::OPT_no_pthread, false); |
73 | |
74 | // If the WASI environment is "threads" then enable pthreads support |
75 | // without requiring -pthread, in order to prevent user error |
76 | if (Triple.isOSWASI() && Triple.getEnvironmentName() == "threads") |
77 | WantsPthread = true; |
78 | |
79 | return WantsPthread; |
80 | } |
81 | |
82 | void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, |
83 | const InputInfo &Output, |
84 | const InputInfoList &Inputs, |
85 | const ArgList &Args, |
86 | const char *LinkingOutput) const { |
87 | |
88 | const ToolChain &ToolChain = getToolChain(); |
89 | const char *Linker = Args.MakeArgString(Str: getLinkerPath(Args)); |
90 | ArgStringList CmdArgs; |
91 | |
92 | CmdArgs.push_back(Elt: "-m"); |
93 | if (ToolChain.getTriple().isArch64Bit()) |
94 | CmdArgs.push_back(Elt: "wasm64"); |
95 | else |
96 | CmdArgs.push_back(Elt: "wasm32"); |
97 | |
98 | if (Args.hasArg(options::OPT_s)) |
99 | CmdArgs.push_back(Elt: "--strip-all"); |
100 | |
101 | // On `wasip2` the default linker is `wasm-component-ld` which wraps the |
102 | // execution of `wasm-ld`. Find `wasm-ld` and pass it as an argument of where |
103 | // to find it to avoid it needing to hunt and rediscover or search `PATH` for |
104 | // where it is. |
105 | if (llvm::sys::path::stem(path: Linker).ends_with_insensitive( |
106 | Suffix: "wasm-component-ld")) { |
107 | CmdArgs.push_back(Elt: "--wasm-ld-path"); |
108 | CmdArgs.push_back(Elt: Args.MakeArgString(Str: ToolChain.GetProgramPath(Name: "wasm-ld"))); |
109 | } |
110 | |
111 | Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u}); |
112 | |
113 | ToolChain.AddFilePathLibArgs(Args, CmdArgs); |
114 | |
115 | bool IsCommand = true; |
116 | const char *Crt1; |
117 | const char *Entry = nullptr; |
118 | |
119 | // When -shared is specified, use the reactor exec model unless |
120 | // specified otherwise. |
121 | if (Args.hasArg(options::OPT_shared)) |
122 | IsCommand = false; |
123 | |
124 | if (const Arg *A = Args.getLastArg(options::OPT_mexec_model_EQ)) { |
125 | StringRef CM = A->getValue(); |
126 | if (CM == "command") { |
127 | IsCommand = true; |
128 | } else if (CM == "reactor") { |
129 | IsCommand = false; |
130 | } else { |
131 | ToolChain.getDriver().Diag(diag::DiagID: err_drv_invalid_argument_to_option) |
132 | << CM << A->getOption().getName(); |
133 | } |
134 | } |
135 | |
136 | if (IsCommand) { |
137 | // If crt1-command.o exists, it supports new-style commands, so use it. |
138 | // Otherwise, use the old crt1.o. This is a temporary transition measure. |
139 | // Once WASI libc no longer needs to support LLVM versions which lack |
140 | // support for new-style command, it can make crt1.o the same as |
141 | // crt1-command.o. And once LLVM no longer needs to support WASI libc |
142 | // versions before that, it can switch to using crt1-command.o. |
143 | Crt1 = "crt1.o"; |
144 | if (ToolChain.GetFilePath(Name: "crt1-command.o") != "crt1-command.o") |
145 | Crt1 = "crt1-command.o"; |
146 | } else { |
147 | Crt1 = "crt1-reactor.o"; |
148 | Entry = "_initialize"; |
149 | } |
150 | |
151 | if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) |
152 | CmdArgs.push_back(Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: Crt1))); |
153 | if (Entry) { |
154 | CmdArgs.push_back(Elt: Args.MakeArgString(Str: "--entry")); |
155 | CmdArgs.push_back(Elt: Args.MakeArgString(Str: Entry)); |
156 | } |
157 | |
158 | if (Args.hasArg(options::OPT_shared)) |
159 | CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-shared")); |
160 | |
161 | AddLinkerInputs(TC: ToolChain, Inputs, Args, CmdArgs, JA); |
162 | |
163 | if (WantsPthread(Triple: ToolChain.getTriple(), Args)) |
164 | CmdArgs.push_back(Elt: "--shared-memory"); |
165 | |
166 | if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { |
167 | if (ToolChain.ShouldLinkCXXStdlib(Args)) |
168 | ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); |
169 | |
170 | if (WantsPthread(Triple: ToolChain.getTriple(), Args)) |
171 | CmdArgs.push_back(Elt: "-lpthread"); |
172 | |
173 | CmdArgs.push_back(Elt: "-lc"); |
174 | AddRunTimeLibs(TC: ToolChain, D: ToolChain.getDriver(), CmdArgs, Args); |
175 | } |
176 | |
177 | ToolChain.addProfileRTLibs(Args, CmdArgs); |
178 | |
179 | CmdArgs.push_back(Elt: "-o"); |
180 | CmdArgs.push_back(Elt: Output.getFilename()); |
181 | |
182 | // Don't use wasm-opt by default on `wasip2` as it doesn't have support for |
183 | // components at this time. Retain the historical default otherwise, though, |
184 | // of running `wasm-opt` by default. |
185 | bool WasmOptDefault = !TargetBuildsComponents(TargetTriple: ToolChain.getTriple()); |
186 | bool RunWasmOpt = Args.hasFlag(options::OPT_wasm_opt, |
187 | options::OPT_no_wasm_opt, WasmOptDefault); |
188 | |
189 | // If wasm-opt is enabled and optimizations are happening look for the |
190 | // `wasm-opt` program. If it's not found auto-disable it. |
191 | std::string WasmOptPath; |
192 | if (RunWasmOpt && Args.getLastArg(options::OPT_O_Group)) { |
193 | WasmOptPath = ToolChain.GetProgramPath(Name: "wasm-opt"); |
194 | if (WasmOptPath == "wasm-opt") { |
195 | WasmOptPath = {}; |
196 | } |
197 | } |
198 | |
199 | if (!WasmOptPath.empty()) { |
200 | CmdArgs.push_back(Elt: "--keep-section=target_features"); |
201 | } |
202 | |
203 | C.addCommand(C: std::make_unique<Command>(args: JA, args: *this, |
204 | args: ResponseFileSupport::AtFileCurCP(), |
205 | args&: Linker, args&: CmdArgs, args: Inputs, args: Output)); |
206 | |
207 | if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { |
208 | if (!WasmOptPath.empty()) { |
209 | StringRef OOpt = "s"; |
210 | if (A->getOption().matches(options::ID: OPT_O4) || |
211 | A->getOption().matches(options::ID: OPT_Ofast)) |
212 | OOpt = "4"; |
213 | else if (A->getOption().matches(options::ID: OPT_O0)) |
214 | OOpt = "0"; |
215 | else if (A->getOption().matches(options::ID: OPT_O)) |
216 | OOpt = A->getValue(); |
217 | |
218 | if (OOpt != "0") { |
219 | const char *WasmOpt = Args.MakeArgString(Str: WasmOptPath); |
220 | ArgStringList OptArgs; |
221 | OptArgs.push_back(Elt: Output.getFilename()); |
222 | OptArgs.push_back(Elt: Args.MakeArgString(Str: llvm::Twine("-O") + OOpt)); |
223 | OptArgs.push_back(Elt: "-o"); |
224 | OptArgs.push_back(Elt: Output.getFilename()); |
225 | C.addCommand(C: std::make_unique<Command>( |
226 | args: JA, args: *this, args: ResponseFileSupport::AtFileCurCP(), args&: WasmOpt, args&: OptArgs, |
227 | args: Inputs, args: Output)); |
228 | } |
229 | } |
230 | } |
231 | } |
232 | |
233 | /// Given a base library directory, append path components to form the |
234 | /// LTO directory. |
235 | static std::string AppendLTOLibDir(const std::string &Dir) { |
236 | // The version allows the path to be keyed to the specific version of |
237 | // LLVM in used, as the bitcode format is not stable. |
238 | return Dir + "/llvm-lto/"LLVM_VERSION_STRING; |
239 | } |
240 | |
241 | WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, |
242 | const llvm::opt::ArgList &Args) |
243 | : ToolChain(D, Triple, Args) { |
244 | |
245 | assert(Triple.isArch32Bit() != Triple.isArch64Bit()); |
246 | |
247 | getProgramPaths().push_back(Elt: getDriver().Dir); |
248 | |
249 | auto SysRoot = getDriver().SysRoot; |
250 | if (getTriple().getOS() == llvm::Triple::UnknownOS) { |
251 | // Theoretically an "unknown" OS should mean no standard libraries, however |
252 | // it could also mean that a custom set of libraries is in use, so just add |
253 | // /lib to the search path. Disable multiarch in this case, to discourage |
254 | // paths containing "unknown" from acquiring meanings. |
255 | getFilePaths().push_back(Elt: SysRoot + "/lib"); |
256 | } else { |
257 | const std::string MultiarchTriple = |
258 | getMultiarchTriple(D: getDriver(), TargetTriple: Triple, SysRoot); |
259 | if (D.isUsingLTO()) { |
260 | // For LTO, enable use of lto-enabled sysroot libraries too, if available. |
261 | // Note that the directory is keyed to the LLVM revision, as LLVM's |
262 | // bitcode format is not stable. |
263 | auto Dir = AppendLTOLibDir(Dir: SysRoot + "/lib/"+ MultiarchTriple); |
264 | getFilePaths().push_back(Elt: Dir); |
265 | } |
266 | getFilePaths().push_back(Elt: SysRoot + "/lib/"+ MultiarchTriple); |
267 | } |
268 | } |
269 | |
270 | const char *WebAssembly::getDefaultLinker() const { |
271 | if (TargetBuildsComponents(TargetTriple: getTriple())) |
272 | return "wasm-component-ld"; |
273 | return "wasm-ld"; |
274 | } |
275 | |
276 | bool WebAssembly::IsMathErrnoDefault() const { return false; } |
277 | |
278 | bool WebAssembly::IsObjCNonFragileABIDefault() const { return true; } |
279 | |
280 | bool WebAssembly::UseObjCMixedDispatch() const { return true; } |
281 | |
282 | bool WebAssembly::isPICDefault() const { return false; } |
283 | |
284 | bool WebAssembly::isPIEDefault(const llvm::opt::ArgList &Args) const { |
285 | return false; |
286 | } |
287 | |
288 | bool WebAssembly::isPICDefaultForced() const { return false; } |
289 | |
290 | bool WebAssembly::hasBlocksRuntime() const { return false; } |
291 | |
292 | // TODO: Support profiling. |
293 | bool WebAssembly::SupportsProfiling() const { return false; } |
294 | |
295 | bool WebAssembly::HasNativeLLVMSupport() const { return true; } |
296 | |
297 | void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, |
298 | ArgStringList &CC1Args, |
299 | Action::OffloadKind) const { |
300 | if (!DriverArgs.hasFlag(clang::driver::options::OPT_fuse_init_array, |
301 | options::OPT_fno_use_init_array, true)) |
302 | CC1Args.push_back(Elt: "-fno-use-init-array"); |
303 | |
304 | // '-pthread' implies atomics, bulk-memory, mutable-globals, and sign-ext |
305 | if (WantsPthread(Triple: getTriple(), Args: DriverArgs)) { |
306 | if (DriverArgs.hasFlag(options::OPT_mno_atomics, options::OPT_matomics, |
307 | false)) |
308 | getDriver().Diag(diag::DiagID: err_drv_argument_not_allowed_with) |
309 | << "-pthread" |
310 | << "-mno-atomics"; |
311 | if (DriverArgs.hasFlag(options::OPT_mno_bulk_memory, |
312 | options::OPT_mbulk_memory, false)) |
313 | getDriver().Diag(diag::DiagID: err_drv_argument_not_allowed_with) |
314 | << "-pthread" |
315 | << "-mno-bulk-memory"; |
316 | if (DriverArgs.hasFlag(options::OPT_mno_mutable_globals, |
317 | options::OPT_mmutable_globals, false)) |
318 | getDriver().Diag(diag::DiagID: err_drv_argument_not_allowed_with) |
319 | << "-pthread" |
320 | << "-mno-mutable-globals"; |
321 | if (DriverArgs.hasFlag(options::OPT_mno_sign_ext, options::OPT_msign_ext, |
322 | false)) |
323 | getDriver().Diag(diag::DiagID: err_drv_argument_not_allowed_with) |
324 | << "-pthread" |
325 | << "-mno-sign-ext"; |
326 | CC1Args.push_back(Elt: "-target-feature"); |
327 | CC1Args.push_back(Elt: "+atomics"); |
328 | CC1Args.push_back(Elt: "-target-feature"); |
329 | CC1Args.push_back(Elt: "+bulk-memory"); |
330 | CC1Args.push_back(Elt: "-target-feature"); |
331 | CC1Args.push_back(Elt: "+mutable-globals"); |
332 | CC1Args.push_back(Elt: "-target-feature"); |
333 | CC1Args.push_back(Elt: "+sign-ext"); |
334 | } |
335 | |
336 | if (!DriverArgs.hasFlag(options::OPT_mmutable_globals, |
337 | options::OPT_mno_mutable_globals, false)) { |
338 | // -fPIC implies +mutable-globals because the PIC ABI used by the linker |
339 | // depends on importing and exporting mutable globals. |
340 | llvm::Reloc::Model RelocationModel; |
341 | unsigned PICLevel; |
342 | bool IsPIE; |
343 | std::tie(args&: RelocationModel, args&: PICLevel, args&: IsPIE) = |
344 | ParsePICArgs(ToolChain: *this, Args: DriverArgs); |
345 | if (RelocationModel == llvm::Reloc::PIC_) { |
346 | if (DriverArgs.hasFlag(options::OPT_mno_mutable_globals, |
347 | options::OPT_mmutable_globals, false)) { |
348 | getDriver().Diag(diag::DiagID: err_drv_argument_not_allowed_with) |
349 | << "-fPIC" |
350 | << "-mno-mutable-globals"; |
351 | } |
352 | CC1Args.push_back(Elt: "-target-feature"); |
353 | CC1Args.push_back(Elt: "+mutable-globals"); |
354 | } |
355 | } |
356 | |
357 | bool HasBannedIncompatibleOptionsForWasmEHSjLj = false; |
358 | bool HasEnabledFeaturesForWasmEHSjLj = false; |
359 | |
360 | // Bans incompatible options for Wasm EH / SjLj. We don't allow using |
361 | // different modes for EH and SjLj. |
362 | auto BanIncompatibleOptionsForWasmEHSjLj = [&](StringRef CurOption) { |
363 | if (HasBannedIncompatibleOptionsForWasmEHSjLj) |
364 | return; |
365 | HasBannedIncompatibleOptionsForWasmEHSjLj = true; |
366 | if (DriverArgs.hasFlag(options::OPT_mno_exception_handing, |
367 | options::OPT_mexception_handing, false)) |
368 | getDriver().Diag(diag::DiagID: err_drv_argument_not_allowed_with) |
369 | << CurOption << "-mno-exception-handling"; |
370 | // The standardized Wasm EH spec requires multivalue and reference-types. |
371 | if (DriverArgs.hasFlag(options::OPT_mno_multivalue, |
372 | options::OPT_mmultivalue, false)) |
373 | getDriver().Diag(diag::DiagID: err_drv_argument_not_allowed_with) |
374 | << CurOption << "-mno-multivalue"; |
375 | if (DriverArgs.hasFlag(options::OPT_mno_reference_types, |
376 | options::OPT_mreference_types, false)) |
377 | getDriver().Diag(diag::err_drv_argument_not_allowed_with) |
378 | << CurOption << "-mno-reference-types"; |
379 | |
380 | for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { |
381 | for (const auto *Option : |
382 | {"-enable-emscripten-cxx-exceptions", "-enable-emscripten-sjlj", |
383 | "-emscripten-cxx-exceptions-allowed"}) { |
384 | if (StringRef(A->getValue(0)) == Option) |
385 | getDriver().Diag(diag::err_drv_argument_not_allowed_with) |
386 | << CurOption << Option; |
387 | } |
388 | } |
389 | }; |
390 | |
391 | // Enable necessary features for Wasm EH / SjLj in the backend. |
392 | auto EnableFeaturesForWasmEHSjLj = [&]() { |
393 | if (HasEnabledFeaturesForWasmEHSjLj) |
394 | return; |
395 | HasEnabledFeaturesForWasmEHSjLj = true; |
396 | CC1Args.push_back(Elt: "-target-feature"); |
397 | CC1Args.push_back(Elt: "+exception-handling"); |
398 | // The standardized Wasm EH spec requires multivalue and reference-types. |
399 | CC1Args.push_back(Elt: "-target-feature"); |
400 | CC1Args.push_back(Elt: "+multivalue"); |
401 | CC1Args.push_back(Elt: "-target-feature"); |
402 | CC1Args.push_back(Elt: "+reference-types"); |
403 | // Backend needs '-exception-model=wasm' to use Wasm EH instructions |
404 | CC1Args.push_back(Elt: "-exception-model=wasm"); |
405 | }; |
406 | |
407 | if (DriverArgs.getLastArg(options::OPT_fwasm_exceptions)) { |
408 | BanIncompatibleOptionsForWasmEHSjLj("-fwasm-exceptions"); |
409 | EnableFeaturesForWasmEHSjLj(); |
410 | // Backend needs -wasm-enable-eh to enable Wasm EH |
411 | CC1Args.push_back(Elt: "-mllvm"); |
412 | CC1Args.push_back(Elt: "-wasm-enable-eh"); |
413 | } |
414 | |
415 | for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { |
416 | StringRef Opt = A->getValue(0); |
417 | if (Opt.starts_with("-emscripten-cxx-exceptions-allowed")) { |
418 | // '-mllvm -emscripten-cxx-exceptions-allowed' should be used with |
419 | // '-mllvm -enable-emscripten-cxx-exceptions' |
420 | bool EmEHArgExists = false; |
421 | for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { |
422 | if (StringRef(A->getValue(0)) == "-enable-emscripten-cxx-exceptions") { |
423 | EmEHArgExists = true; |
424 | break; |
425 | } |
426 | } |
427 | if (!EmEHArgExists) |
428 | getDriver().Diag(diag::err_drv_argument_only_allowed_with) |
429 | << "-mllvm -emscripten-cxx-exceptions-allowed" |
430 | << "-mllvm -enable-emscripten-cxx-exceptions"; |
431 | |
432 | // Prevent functions specified in -emscripten-cxx-exceptions-allowed list |
433 | // from being inlined before reaching the wasm backend. |
434 | StringRef FuncNamesStr = Opt.split('=').second; |
435 | SmallVector<StringRef, 4> FuncNames; |
436 | FuncNamesStr.split(FuncNames, ','); |
437 | for (auto Name : FuncNames) { |
438 | CC1Args.push_back("-mllvm"); |
439 | CC1Args.push_back(DriverArgs.MakeArgString("--force-attribute="+ Name + |
440 | ":noinline")); |
441 | } |
442 | } |
443 | |
444 | for (const auto *Option : |
445 | {"-wasm-enable-eh", "-wasm-enable-sjlj", "-wasm-use-legacy-eh"}) { |
446 | if (Opt.starts_with(Option)) { |
447 | BanIncompatibleOptionsForWasmEHSjLj(Option); |
448 | EnableFeaturesForWasmEHSjLj(); |
449 | } |
450 | } |
451 | } |
452 | } |
453 | |
454 | ToolChain::RuntimeLibType WebAssembly::GetDefaultRuntimeLibType() const { |
455 | return ToolChain::RLT_CompilerRT; |
456 | } |
457 | |
458 | ToolChain::CXXStdlibType |
459 | WebAssembly::GetCXXStdlibType(const ArgList &Args) const { |
460 | if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { |
461 | StringRef Value = A->getValue(); |
462 | if (Value == "libc++") |
463 | return ToolChain::CST_Libcxx; |
464 | else if (Value == "libstdc++") |
465 | return ToolChain::CST_Libstdcxx; |
466 | else |
467 | getDriver().Diag(diag::err_drv_invalid_stdlib_name) |
468 | << A->getAsString(Args); |
469 | } |
470 | return ToolChain::CST_Libcxx; |
471 | } |
472 | |
473 | void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs, |
474 | ArgStringList &CC1Args) const { |
475 | if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) |
476 | return; |
477 | |
478 | const Driver &D = getDriver(); |
479 | |
480 | if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { |
481 | SmallString<128> P(D.ResourceDir); |
482 | llvm::sys::path::append(path&: P, a: "include"); |
483 | addSystemInclude(DriverArgs, CC1Args, Path: P); |
484 | } |
485 | |
486 | if (DriverArgs.hasArg(options::OPT_nostdlibinc)) |
487 | return; |
488 | |
489 | // Check for configure-time C include directories. |
490 | StringRef CIncludeDirs(C_INCLUDE_DIRS); |
491 | if (CIncludeDirs != "") { |
492 | SmallVector<StringRef, 5> dirs; |
493 | CIncludeDirs.split(A&: dirs, Separator: ":"); |
494 | for (StringRef dir : dirs) { |
495 | StringRef Prefix = |
496 | llvm::sys::path::is_absolute(path: dir) ? "": StringRef(D.SysRoot); |
497 | addExternCSystemInclude(DriverArgs, CC1Args, Path: Prefix + dir); |
498 | } |
499 | return; |
500 | } |
501 | |
502 | if (getTriple().getOS() != llvm::Triple::UnknownOS) { |
503 | const std::string MultiarchTriple = |
504 | getMultiarchTriple(D, TargetTriple: getTriple(), SysRoot: D.SysRoot); |
505 | addSystemInclude(DriverArgs, CC1Args, Path: D.SysRoot + "/include/"+ MultiarchTriple); |
506 | } |
507 | addSystemInclude(DriverArgs, CC1Args, Path: D.SysRoot + "/include"); |
508 | } |
509 | |
510 | void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, |
511 | ArgStringList &CC1Args) const { |
512 | |
513 | if (DriverArgs.hasArg(options::OPT_nostdlibinc, options::OPT_nostdinc, |
514 | options::OPT_nostdincxx)) |
515 | return; |
516 | |
517 | switch (GetCXXStdlibType(Args: DriverArgs)) { |
518 | case ToolChain::CST_Libcxx: |
519 | addLibCxxIncludePaths(DriverArgs, CC1Args); |
520 | break; |
521 | case ToolChain::CST_Libstdcxx: |
522 | addLibStdCXXIncludePaths(DriverArgs, CC1Args); |
523 | break; |
524 | } |
525 | } |
526 | |
527 | void WebAssembly::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, |
528 | llvm::opt::ArgStringList &CmdArgs) const { |
529 | |
530 | switch (GetCXXStdlibType(Args)) { |
531 | case ToolChain::CST_Libcxx: |
532 | CmdArgs.push_back(Elt: "-lc++"); |
533 | if (Args.hasArg(options::OPT_fexperimental_library)) |
534 | CmdArgs.push_back(Elt: "-lc++experimental"); |
535 | CmdArgs.push_back(Elt: "-lc++abi"); |
536 | break; |
537 | case ToolChain::CST_Libstdcxx: |
538 | CmdArgs.push_back(Elt: "-lstdc++"); |
539 | break; |
540 | } |
541 | } |
542 | |
543 | SanitizerMask WebAssembly::getSupportedSanitizers() const { |
544 | SanitizerMask Res = ToolChain::getSupportedSanitizers(); |
545 | if (getTriple().isOSEmscripten()) { |
546 | Res |= SanitizerKind::Vptr | SanitizerKind::Leak; |
547 | } |
548 | |
549 | if (getTriple().isOSEmscripten() || getTriple().isOSWASI()) { |
550 | Res |= SanitizerKind::Address; |
551 | } |
552 | |
553 | // -fsanitize=function places two words before the function label, which are |
554 | // -unsupported. |
555 | Res &= ~SanitizerKind::Function; |
556 | return Res; |
557 | } |
558 | |
559 | Tool *WebAssembly::buildLinker() const { |
560 | return new tools::wasm::Linker(*this); |
561 | } |
562 | |
563 | void WebAssembly::addLibCxxIncludePaths( |
564 | const llvm::opt::ArgList &DriverArgs, |
565 | llvm::opt::ArgStringList &CC1Args) const { |
566 | const Driver &D = getDriver(); |
567 | std::string SysRoot = computeSysRoot(); |
568 | std::string LibPath = SysRoot + "/include"; |
569 | const std::string MultiarchTriple = |
570 | getMultiarchTriple(D, TargetTriple: getTriple(), SysRoot); |
571 | bool IsKnownOs = (getTriple().getOS() != llvm::Triple::UnknownOS); |
572 | |
573 | std::string Version = detectLibcxxVersion(IncludePath: LibPath); |
574 | if (Version.empty()) |
575 | return; |
576 | |
577 | // First add the per-target include path if the OS is known. |
578 | if (IsKnownOs) { |
579 | std::string TargetDir = LibPath + "/"+ MultiarchTriple + "/c++/"+ Version; |
580 | addSystemInclude(DriverArgs, CC1Args, Path: TargetDir); |
581 | } |
582 | |
583 | // Second add the generic one. |
584 | addSystemInclude(DriverArgs, CC1Args, Path: LibPath + "/c++/"+ Version); |
585 | } |
586 | |
587 | void WebAssembly::addLibStdCXXIncludePaths( |
588 | const llvm::opt::ArgList &DriverArgs, |
589 | llvm::opt::ArgStringList &CC1Args) const { |
590 | // We cannot use GCCInstallationDetector here as the sysroot usually does |
591 | // not contain a full GCC installation. |
592 | // Instead, we search the given sysroot for /usr/include/xx, similar |
593 | // to how we do it for libc++. |
594 | const Driver &D = getDriver(); |
595 | std::string SysRoot = computeSysRoot(); |
596 | std::string LibPath = SysRoot + "/include"; |
597 | const std::string MultiarchTriple = |
598 | getMultiarchTriple(D, TargetTriple: getTriple(), SysRoot); |
599 | bool IsKnownOs = (getTriple().getOS() != llvm::Triple::UnknownOS); |
600 | |
601 | // This is similar to detectLibcxxVersion() |
602 | std::string Version; |
603 | { |
604 | std::error_code EC; |
605 | Generic_GCC::GCCVersion MaxVersion = |
606 | Generic_GCC::GCCVersion::Parse(VersionText: "0.0.0"); |
607 | SmallString<128> Path(LibPath); |
608 | llvm::sys::path::append(path&: Path, a: "c++"); |
609 | for (llvm::vfs::directory_iterator LI = getVFS().dir_begin(Dir: Path, EC), LE; |
610 | !EC && LI != LE; LI = LI.increment(EC)) { |
611 | StringRef VersionText = llvm::sys::path::filename(path: LI->path()); |
612 | if (VersionText[0] != 'v') { |
613 | auto Version = Generic_GCC::GCCVersion::Parse(VersionText); |
614 | if (Version > MaxVersion) |
615 | MaxVersion = Version; |
616 | } |
617 | } |
618 | if (MaxVersion.Major > 0) |
619 | Version = MaxVersion.Text; |
620 | } |
621 | |
622 | if (Version.empty()) |
623 | return; |
624 | |
625 | // First add the per-target include path if the OS is known. |
626 | if (IsKnownOs) { |
627 | std::string TargetDir = LibPath + "/c++/"+ Version + "/"+ MultiarchTriple; |
628 | addSystemInclude(DriverArgs, CC1Args, Path: TargetDir); |
629 | } |
630 | |
631 | // Second add the generic one. |
632 | addSystemInclude(DriverArgs, CC1Args, Path: LibPath + "/c++/"+ Version); |
633 | // Third the backward one. |
634 | addSystemInclude(DriverArgs, CC1Args, Path: LibPath + "/c++/"+ Version + "/backward"); |
635 | } |
636 |
Definitions
- getMultiarchTriple
- getLinkerPath
- TargetBuildsComponents
- WantsPthread
- ConstructJob
- AppendLTOLibDir
- WebAssembly
- getDefaultLinker
- IsMathErrnoDefault
- IsObjCNonFragileABIDefault
- UseObjCMixedDispatch
- isPICDefault
- isPIEDefault
- isPICDefaultForced
- hasBlocksRuntime
- SupportsProfiling
- HasNativeLLVMSupport
- addClangTargetOptions
- GetDefaultRuntimeLibType
- GetCXXStdlibType
- AddClangSystemIncludeArgs
- AddClangCXXStdlibIncludeArgs
- AddCXXStdlibLibArgs
- getSupportedSanitizers
- buildLinker
- addLibCxxIncludePaths
Improve your Profiling and Debugging skills
Find out more