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