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