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