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