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