[clang] [clang] Support --sysroot= for ${arch}-windows-msvc targets (PR #96417)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 20 20:55:44 PDT 2026
https://github.com/trcrsired updated https://github.com/llvm/llvm-project/pull/96417
>From eedd17262836ca8872b53027c0893f92e6cb41b1 Mon Sep 17 00:00:00 2001
From: trcrsired <uwgghhbcad at gmail.com>
Date: Thu, 20 Aug 2026 14:05:33 +0800
Subject: [PATCH 01/10] [clang] Support --sysroot= for ${arch}-windows-msvc
targets
I think it is possible to use the same rule for msvc targets with --target= and --sysroot=
See Repository:
https://github.com/trcrsired/windows-msvc-sysroot
Headers
Windows + CRT Headers Include Directory: include
C++ standard library headers:
With -stdlib=stl, headers should be located in include/c++/stl
(To change: -stdlib=msstl, headers should be located in include/c++/msstl)
With -stdlib=libc++, headers should be located in include/c++/v1
With -stdlib=libstdc++, headers should be located in include/c++/16.0.0 (GCC version)
Libraries
Libraries should be placed in lib/$TRIPLET
Bins
Bins should be placed in bin/$TRIPLET
For example. on x86_64-unknown-windows-msvc, it should find libs in lib/x86_64-unknown-windows-msvc
Furthermore, clang --sysroot also accepts clang-cl /winsysroot.
---
clang/docs/UsersManual.md | 63 +++++
clang/include/clang/Driver/ToolChain.h | 16 +-
clang/lib/Driver/Driver.cpp | 102 ++++----
clang/lib/Driver/ToolChain.cpp | 12 +
clang/lib/Driver/ToolChains/MSVC.cpp | 327 +++++++++++++++++++++----
clang/lib/Driver/ToolChains/MSVC.h | 15 ++
clang/test/Driver/msvc-sysroot.cpp | 128 ++++++++++
7 files changed, 558 insertions(+), 105 deletions(-)
create mode 100644 clang/test/Driver/msvc-sysroot.cpp
diff --git a/clang/docs/UsersManual.md b/clang/docs/UsersManual.md
index 40834746e1218..7c6c844dee1cd 100644
--- a/clang/docs/UsersManual.md
+++ b/clang/docs/UsersManual.md
@@ -6405,3 +6405,66 @@ The Visual C++ Toolset has a slightly more elaborate mechanism for detection.
Strict aliasing (TBAA) is always off by default in clang-cl whereas in clang,
strict aliasing is turned on by default for all optimization levels. For more
details, see {ref}`Strict aliasing <strict_aliasing>`.
+
+## Using clang/clang++ with MSVC Targets
+
+Clang can use the generic, GCC-style driver command line syntax to generate native Windows artifacts, and users porting a build from a POSIX environment may prefer this interface for consistency across platforms.
+
+When targeting MSVC environments, Clang supports `--target=` and `--sysroot=` following Unix-style cross‑compilation conventions. `--sysroot=` accepts both Unix-style paths and `clang-cl /winsysroot` style paths.
+
+This approach avoids reliance on a Windows environment, Wine, or environment variables, instead using a predictable and portable sysroot layout.
+
+### Headers
+
+- Windows + CRT headers: `include/`
+
+- C++ standard library headers (selected via `-stdlib=`):
+ - `-stdlib=msvcstl` → `include/c++/msvcstl`
+ Microsoft STL (MSVC's standard library implementation)
+ - `-stdlib=libc++` → `include/c++/v1`
+ LLVM libc++ (Clang's standard library implementation)
+ - `-stdlib=libstdc++` → `include/c++/<version>` (e.g. `17.0.0`)
+ GNU libstdc++ (GCC's standard library implementation)
+
+### Library Naming Conventions
+
+When targeting `${cpu}-unknown-windows-msvc`, runtime library naming differs from GNU-style targets:
+
+- **LLVM libc++**
+ - MSVC target: `c++.dll`, `c++.lib`
+ - GNU target: `libc++.dll`, `libc++.a`
+
+- **GNU libstdc++**
+ - MSVC target: `stdc++-6.dll`, `stdc++.lib`
+ - GNU target: `libstdc++-6.dll`, `libstdc++.a`
+
+MSVC targets omit the `lib` prefix and use `.lib` import libraries, while GNU targets retain traditional Unix-style naming.
+
+### Libraries
+
+The sysroot must contain libraries in the following fallback order:
+
+1. `lib/${cpu}-unknown-windows-msvc`
+2. `lib/`
+
+Example for `x86_64-unknown-windows-msvc`:
+lib/x86_64-unknown-windows-msvc → lib/
+This structure supports both target-specific and shared libraries.
+
+### Binaries
+
+The sysroot must contain binaries in the following fallback order:
+
+1. `bin/${cpu}-unknown-windows-msvc`
+2. `bin/`
+
+Example for `x86_64-unknown-windows-msvc`:
+bin/x86_64-unknown-windows-msvc → bin/
+
+This layout supports future scenarios such as universal binaries and ensures consistent tool resolution across architectures.
+
+### Case Sensitivity
+
+All header and library paths must use lowercase file names. This ensures compatibility across case-sensitive filesystems such as Linux and macOS, and matches the behavior of `mingw-w64-crt`. Windows itself is case-insensitive, but relying on mixed-case paths can lead to portability issues.
+
+This layout is fully compatible with Clang’s standard sysroot resolution logic and requires no MSVC-specific flags. It enables clean cross-compilation workflows and portable toolchain packaging.
diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h
index c5633e10933e8..d1db6e7ba1cee 100644
--- a/clang/include/clang/Driver/ToolChain.h
+++ b/clang/include/clang/Driver/ToolChain.h
@@ -98,20 +98,14 @@ class ToolChain {
using path_list = SmallVector<std::string, 16>;
enum CXXStdlibType {
- CST_Libcxx,
- CST_Libstdcxx
+ CST_Libcxx, // LLVM libc++
+ CST_Libstdcxx, // GNU libstdc++
+ CST_Msvcstl, // MSVC STL
};
- enum RuntimeLibType {
- RLT_CompilerRT,
- RLT_Libgcc
- };
+ enum RuntimeLibType { RLT_CompilerRT, RLT_Libgcc, RLT_Vcruntime };
- enum UnwindLibType {
- UNW_None,
- UNW_CompilerRT,
- UNW_Libgcc
- };
+ enum UnwindLibType { UNW_None, UNW_CompilerRT, UNW_Libgcc, UNW_Vcruntime };
enum CStdlibType {
CST_Newlib,
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index c2b670d8edd11..50a6893fbbe1a 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -2801,6 +2801,8 @@ bool Driver::HandleImmediateArgs(Compilation &C) {
case ToolChain::RLT_Libgcc:
llvm::outs() << GetFilePath("libgcc.a", TC) << "\n";
break;
+ default:
+ break;
}
return false;
}
@@ -6996,6 +6998,48 @@ std::string Driver::GetProgramPath(StringRef Name, const ToolChain &TC) const {
return std::string(Name);
}
+static std::optional<std::string>
+CxxModulePathEvaluate(const Driver &D, const ToolChain &TC,
+ ToolChain::CXXStdlibType cxxstdlib, const char *library) {
+ const char *modulejsonfilename = "modules.json";
+ switch (cxxstdlib) {
+ case ToolChain::CST_Libcxx: {
+ // Note when there are multiple flavours of libc++ the module json needs
+ // to look at the command-line arguments for the proper json. These
+ // flavours do not exist at the moment, but there are plans to provide a
+ // variant that is built with sanitizer instrumentation enabled.
+
+ // For example
+ // const SanitizerArgs &Sanitize = TC.getSanitizerArgs(C.getArgs());
+ // if (Sanitize.needsAsanRt())
+ // modulejsonfilename = "libc++.modules-asan.json";
+ // modulejsonfilename = "libc++.modules.json";
+ modulejsonfilename = "libc++.modules.json";
+ break;
+ }
+ case ToolChain::CST_Libstdcxx: {
+ modulejsonfilename = "libstdc++.modules.json";
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ if (library == nullptr) {
+ library = modulejsonfilename;
+ }
+ std::string lib = D.GetFilePath(library, TC);
+
+ SmallString<128> path(lib.begin(), lib.end());
+ llvm::sys::path::remove_filename(path);
+ llvm::sys::path::append(path, modulejsonfilename);
+ if (TC.getVFS().exists(path))
+ return static_cast<std::string>(path);
+
+ return {};
+}
+
std::string Driver::GetStdModuleManifestPath(const Compilation &C,
const ToolChain &TC) const {
std::string error = "<NOT PRESENT>";
@@ -7003,56 +7047,30 @@ std::string Driver::GetStdModuleManifestPath(const Compilation &C,
if (C.getArgs().hasArg(options::OPT_nostdlib))
return error;
- switch (TC.GetCXXStdlibType(C.getArgs())) {
+ auto cxxstdlib = TC.GetCXXStdlibType(C.getArgs());
+ switch (cxxstdlib) {
case ToolChain::CST_Libcxx: {
- auto evaluate = [&](const char *library) -> std::optional<std::string> {
- std::string lib = GetFilePath(library, TC);
-
- // Note when there are multiple flavours of libc++ the module json needs
- // to look at the command-line arguments for the proper json. These
- // flavours do not exist at the moment, but there are plans to provide a
- // variant that is built with sanitizer instrumentation enabled.
-
- // For example
- // StringRef modules = [&] {
- // const SanitizerArgs &Sanitize = TC.getSanitizerArgs(C.getArgs());
- // if (Sanitize.needsAsanRt())
- // return "libc++.modules-asan.json";
- // return "libc++.modules.json";
- // }();
-
- SmallString<128> path(lib.begin(), lib.end());
- llvm::sys::path::remove_filename(path);
- llvm::sys::path::append(path, "libc++.modules.json");
- if (TC.getVFS().exists(path))
- return static_cast<std::string>(path);
-
- return {};
- };
-
- if (std::optional<std::string> result = evaluate("libc++.so"); result)
+ if (std::optional<std::string> result =
+ CxxModulePathEvaluate(*this, TC, cxxstdlib, "libc++.so");
+ result)
return *result;
- return evaluate("libc++.a").value_or(error);
+ return CxxModulePathEvaluate(*this, TC, cxxstdlib, "libc++.a")
+ .value_or(error);
}
case ToolChain::CST_Libstdcxx: {
- auto evaluate = [&](const char *library) -> std::optional<std::string> {
- std::string lib = GetFilePath(library, TC);
-
- SmallString<128> path(lib.begin(), lib.end());
- llvm::sys::path::remove_filename(path);
- llvm::sys::path::append(path, "libstdc++.modules.json");
- if (TC.getVFS().exists(path))
- return static_cast<std::string>(path);
-
- return {};
- };
-
- if (std::optional<std::string> result = evaluate("libstdc++.so"); result)
+ if (std::optional<std::string> result =
+ CxxModulePathEvaluate(*this, TC, cxxstdlib, "libstdc++.so");
+ result)
return *result;
- return evaluate("libstdc++.a").value_or(error);
+ return CxxModulePathEvaluate(*this, TC, cxxstdlib, "libstdc++.a")
+ .value_or(error);
+ }
+
+ default: {
+ return CxxModulePathEvaluate(*this, TC, cxxstdlib, nullptr).value_or(error);
}
}
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 37db75a1bfc14..85201ec2baa40 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -1562,6 +1562,8 @@ ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType(
runtimeLibType = ToolChain::RLT_CompilerRT;
else if (LibName == "libgcc")
runtimeLibType = ToolChain::RLT_Libgcc;
+ else if (LibName == "vcruntime")
+ runtimeLibType = ToolChain::RLT_Vcruntime;
else if (LibName == "platform")
runtimeLibType = GetDefaultRuntimeLibType();
else {
@@ -1601,6 +1603,8 @@ ToolChain::UnwindLibType ToolChain::GetUnwindLibType(
unwindLibType = ToolChain::UNW_CompilerRT;
} else if (LibName == "libgcc")
unwindLibType = ToolChain::UNW_Libgcc;
+ else if (LibName == "vcruntime")
+ unwindLibType = ToolChain::UNW_Vcruntime;
else {
if (A)
getDriver().Diag(diag::err_drv_invalid_unwindlib_name)
@@ -1624,6 +1628,8 @@ ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{
cxxStdlibType = ToolChain::CST_Libcxx;
else if (LibName == "libstdc++")
cxxStdlibType = ToolChain::CST_Libstdcxx;
+ else if (LibName == "msvcstl")
+ cxxStdlibType = ToolChain::CST_Msvcstl;
else if (LibName == "platform")
cxxStdlibType = GetDefaultCXXStdlibType();
else {
@@ -1643,6 +1649,8 @@ StringRef ToolChain::GetCXXStdlibName(const ArgList &Args) const {
return "libc++";
case ToolChain::CST_Libstdcxx:
return "libstdc++";
+ case ToolChain::CST_Msvcstl:
+ return "msvcstl";
}
llvm_unreachable("unknown C++ standard library type");
}
@@ -1814,6 +1822,10 @@ void ToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
case ToolChain::CST_Libstdcxx:
CmdArgs.push_back("-lstdc++");
break;
+
+ case ToolChain::CST_Msvcstl:
+ // MSVC STL does not need to add -l
+ break;
}
}
diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp
index 84bc2db6d2913..66afdb6213db4 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -8,6 +8,7 @@
#include "MSVC.h"
#include "Darwin.h"
+#include "Gnu.h"
#include "clang/Config/config.h"
#include "clang/Driver/CommonArgs.h"
#include "clang/Driver/Compilation.h"
@@ -62,6 +63,30 @@ static std::string FindVisualStudioExecutable(const ToolChain &TC,
return std::string(canExecute(TC.getVFS(), FilePath) ? FilePath.str() : Exe);
}
+// Finds the highest versioned directory (lexically) in a given path.
+// If IsWinSDK is true, it filters for directories starting with "10.".
+static std::string getHighestVersion(llvm::vfs::FileSystem &VFS,
+ StringRef BasePath) {
+ std::string HighestVersion;
+ llvm::VersionTuple MaxVersion;
+ std::error_code EC;
+
+ for (llvm::vfs::directory_iterator LI = VFS.dir_begin(BasePath, EC), LE;
+ !EC && LI != LE; LI = LI.increment(EC)) {
+ StringRef VerText = llvm::sys::path::filename(LI->path());
+
+ llvm::VersionTuple CurrentVersion;
+ if (CurrentVersion.tryParse(VerText))
+ continue;
+
+ if (CurrentVersion > MaxVersion) {
+ MaxVersion = CurrentVersion;
+ HighestVersion = VerText.str();
+ }
+ }
+ return HighestVersion;
+}
+
void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -140,50 +165,110 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- // If the VC environment hasn't been configured (perhaps because the user
- // did not run vcvarsall), try to build a consistent link environment. If
- // the environment variable is set however, assume the user knows what
- // they're doing. If the user passes /vctoolsdir or /winsdkdir, trust that
- // over env vars.
- if (const Arg *A = Args.getLastArg(options::OPT__SLASH_diasdkdir,
- options::OPT__SLASH_winsysroot)) {
- // cl.exe doesn't find the DIA SDK automatically, so this too requires
- // explicit flags and doesn't automatically look in "DIA SDK" relative
- // to the path we found for VCToolChainPath.
- llvm::SmallString<128> DIAPath(A->getValue());
- if (A->getOption().getID() == options::OPT__SLASH_winsysroot)
- llvm::sys::path::append(DIAPath, "DIA SDK");
+ auto SysRoot = TC.getDriver().SysRoot;
+ if (!SysRoot.empty()) {
+
+ // --- 1. GNU-STYLE DETECTION
+ // If we have --sysroot, then we ignore all other setings
+ // libpath is $SYSROOT/lib and $SYSROOT/lib/${ARCH}-unknown-windows-msvc
+ // For ARM64EC, the ARCH is aarch64 instead
+ auto triple = TC.getTriple();
+ const std::string MultiarchTriple =
+ TC.getMultiarchTriple(TC.getDriver(), triple, SysRoot);
+ std::string SysRootLib = "-libpath:" + SysRoot + "/lib";
+ CmdArgs.push_back(Args.MakeArgString(SysRootLib + '/' + MultiarchTriple));
+ if (triple.isWindowsArm64EC()) {
+ triple.setArch(triple.getArch());
+ const std::string NoSubArchMultiarchTriple =
+ TC.getMultiarchTriple(TC.getDriver(), triple, SysRoot);
+ CmdArgs.push_back(
+ Args.MakeArgString(SysRootLib + '/' + NoSubArchMultiarchTriple));
+ }
+ CmdArgs.push_back(Args.MakeArgString(SysRootLib));
+
+ // --- 2. MSVC-STYLE DETECTION (Only if Windows Kits exists) ---
+ auto &VFS = TC.getVFS();
+ std::string WinKitsBase = SysRoot + "/Windows Kits";
+
+ if (VFS.exists(WinKitsBase)) {
+ const char *Arch = llvm::archToWindowsSDKArch(TC.getArch());
+
+ // Windows SDK Discovery
+ std::string SDKRootVer = getHighestVersion(VFS, WinKitsBase);
+ if (!SDKRootVer.empty()) {
+ std::string SDKLibBase = WinKitsBase + "/" + SDKRootVer + "/Lib";
+
+ std::string SDKBuildVer = getHighestVersion(VFS, SDKLibBase);
+ if (!SDKBuildVer.empty()) {
+ std::string SDKLib = SDKLibBase + "/" + SDKBuildVer;
+ CmdArgs.push_back(
+ Args.MakeArgString("-libpath:" + SDKLib + "/ucrt/" + Arch));
+ CmdArgs.push_back(
+ Args.MakeArgString("-libpath:" + SDKLib + "/um/" + Arch));
+ }
+ }
- // The DIA SDK always uses the legacy vc arch, even in new MSVC versions.
- llvm::sys::path::append(DIAPath, "lib",
- llvm::archToLegacyVCArch(TC.getArch()));
- CmdArgs.push_back(Args.MakeArgString(Twine("-libpath:") + DIAPath));
- }
- if (!llvm::sys::Process::GetEnv("LIB") ||
- Args.hasArg(options::OPT__SLASH_vctoolsdir,
- options::OPT__SLASH_vctoolsversion,
- options::OPT__SLASH_winsysroot)) {
- CmdArgs.push_back(Args.MakeArgString(
- Twine("-libpath:") +
- TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib)));
- CmdArgs.push_back(Args.MakeArgString(
- Twine("-libpath:") +
- TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib, "atlmfc")));
- }
- if (!llvm::sys::Process::GetEnv("LIB") ||
- Args.hasArg(options::OPT__SLASH_winsdkdir,
- options::OPT__SLASH_winsdkversion,
- options::OPT__SLASH_winsysroot)) {
- if (TC.useUniversalCRT()) {
- std::string UniversalCRTLibPath;
- if (TC.getUniversalCRTLibraryPath(Args, UniversalCRTLibPath))
+ // MSVC Libs
+ std::string VCToolsBase = SysRoot + "/VC/Tools/MSVC";
+ std::string VCVer = getHighestVersion(VFS, VCToolsBase);
+ if (!VCVer.empty()) {
+ std::string VCLib = VCToolsBase + "/" + VCVer + "/lib/" + Arch;
+ CmdArgs.push_back(Args.MakeArgString("-libpath:" + VCLib));
+ CmdArgs.push_back(Args.MakeArgString("-libpath:" + VCLib + "/atlmfc"));
+ }
+
+ // DIA SDK
+ std::string DIALib =
+ SysRoot + "/DIA SDK/lib/" + llvm::archToLegacyVCArch(TC.getArch());
+ if (VFS.exists(DIALib))
+ CmdArgs.push_back(Args.MakeArgString("-libpath:" + DIALib));
+ }
+ } else {
+ // If the VC environment hasn't been configured (perhaps because the user
+ // did not run vcvarsall), try to build a consistent link environment. If
+ // the environment variable is set however, assume the user knows what
+ // they're doing. If the user passes /vctoolsdir or /winsdkdir, trust that
+ // over env vars.
+ if (const Arg *A = Args.getLastArg(options::OPT__SLASH_diasdkdir,
+ options::OPT__SLASH_winsysroot)) {
+ // cl.exe doesn't find the DIA SDK automatically, so this too requires
+ // explicit flags and doesn't automatically look in "DIA SDK" relative
+ // to the path we found for VCToolChainPath.
+ llvm::SmallString<128> DIAPath(A->getValue());
+ if (A->getOption().getID() == options::OPT__SLASH_winsysroot)
+ llvm::sys::path::append(DIAPath, "DIA SDK");
+
+ // The DIA SDK always uses the legacy vc arch, even in new MSVC versions.
+ llvm::sys::path::append(DIAPath, "lib",
+ llvm::archToLegacyVCArch(TC.getArch()));
+ CmdArgs.push_back(Args.MakeArgString(Twine("-libpath:") + DIAPath));
+ }
+ if (!llvm::sys::Process::GetEnv("LIB") ||
+ Args.hasArg(options::OPT__SLASH_vctoolsdir,
+ options::OPT__SLASH_vctoolsversion,
+ options::OPT__SLASH_winsysroot)) {
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine("-libpath:") +
+ TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib)));
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine("-libpath:") +
+ TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib, "atlmfc")));
+ }
+ if (!llvm::sys::Process::GetEnv("LIB") ||
+ Args.hasArg(options::OPT__SLASH_winsdkdir,
+ options::OPT__SLASH_winsdkversion,
+ options::OPT__SLASH_winsysroot)) {
+ if (TC.useUniversalCRT()) {
+ std::string UniversalCRTLibPath;
+ if (TC.getUniversalCRTLibraryPath(Args, UniversalCRTLibPath))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath));
+ }
+ std::string WindowsSdkLibPath;
+ if (TC.getWindowsSDKLibraryPath(Args, WindowsSdkLibPath))
CmdArgs.push_back(
- Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath));
+ Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
}
- std::string WindowsSdkLibPath;
- if (TC.getWindowsSDKLibraryPath(Args, WindowsSdkLibPath))
- CmdArgs.push_back(
- Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
}
if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L))
@@ -533,6 +618,12 @@ MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
RocmInstallation(D, Triple, Args), SYCLInstallation(D, Triple, Args) {
getProgramPaths().push_back(getDriver().Dir);
+ auto SysRoot = getDriver().SysRoot;
+ if (!SysRoot.empty()) {
+ // We have sysroot so we ignore all VCTools settings
+ return;
+ }
+
std::optional<llvm::StringRef> VCToolsDir, VCToolsVersion;
if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir))
VCToolsDir = A->getValue();
@@ -819,6 +910,50 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
"include");
}
+ auto SysRoot = getDriver().SysRoot;
+ if (!SysRoot.empty()) {
+ const Driver &D = getDriver();
+ const std::string MultiarchTriple =
+ getMultiarchTriple(D, getTriple(), SysRoot);
+
+ // --- 1. GNU-style Headers ---
+ addSystemInclude(DriverArgs, CC1Args,
+ SysRoot + "/include/" + MultiarchTriple);
+ addSystemInclude(DriverArgs, CC1Args, SysRoot + "/include");
+
+ // 2. MSVC-style (Only if Windows Kits exists)
+ auto &VFS = getVFS();
+ std::string WinKitsBase = SysRoot + "/Windows Kits";
+
+ if (VFS.exists(WinKitsBase)) {
+ // Find SDK Root (e.g., "10" or "11")
+ std::string SDKRootVer = getHighestVersion(VFS, WinKitsBase);
+
+ if (!SDKRootVer.empty()) {
+ std::string SDKIncBase = WinKitsBase + "/" + SDKRootVer + "/Include";
+
+ // Find Specific SDK Build Version (e.g., "10.0.19041.0")
+ std::string SDKBuildVer = getHighestVersion(VFS, SDKIncBase);
+ if (!SDKBuildVer.empty()) {
+ std::string SDKPath = SDKIncBase + "/" + SDKBuildVer;
+ addSystemInclude(DriverArgs, CC1Args, SDKPath + "/ucrt");
+ addSystemInclude(DriverArgs, CC1Args, SDKPath + "/um");
+ addSystemInclude(DriverArgs, CC1Args, SDKPath + "/shared");
+ }
+ }
+
+ // VC Tools Discovery
+ std::string VCToolsBase = SysRoot + "/VC/Tools/MSVC";
+ std::string VCVer = getHighestVersion(VFS, VCToolsBase);
+ if (!VCVer.empty()) {
+ std::string VCInc = VCToolsBase + "/" + VCVer + "/include";
+ addSystemInclude(DriverArgs, CC1Args, VCInc);
+ addSystemInclude(DriverArgs, CC1Args, VCInc + "/atlmfc");
+ }
+ }
+ return;
+ }
+
// Add %INCLUDE%-like directories from the -imsvc flag.
for (const auto &Path : DriverArgs.getAllArgValues(options::OPT__SLASH_imsvc))
addSystemInclude(DriverArgs, CC1Args, Path);
@@ -953,17 +1088,22 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- // MSVC STL paths are added from AddClangSystemIncludeArgs during normal
- // compilation to preserve clang-cl header search order.
- if (DriverArgs.hasArg(options::OPT_print_cxx_stdlib_include_dirs) &&
- !DriverArgs.hasArg(options::OPT_stdlib_EQ))
- AddMSVCStdlibIncludeArgs(DriverArgs, CC1Args);
-}
-
-StringRef MSVCToolChain::GetCXXStdlibName(const ArgList &DriverArgs) const {
- if (!DriverArgs.hasArg(options::OPT_stdlib_EQ))
- return "msvcstl";
- return ToolChain::GetCXXStdlibName(DriverArgs);
+ if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
+ options::OPT_nostdincxx))
+ return;
+ if (getDriver().SysRoot.empty())
+ return;
+ switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Msvcstl:
+ addMsvcstlIncludePaths(DriverArgs, CC1Args);
+ break;
+ case ToolChain::CST_Libstdcxx:
+ addLibStdCXXIncludePaths(DriverArgs, CC1Args);
+ break;
+ case ToolChain::CST_Libcxx:
+ addLibCxxIncludePaths(DriverArgs, CC1Args);
+ break;
+ }
}
VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D,
@@ -1216,3 +1356,86 @@ void MSVCToolChain::addClangTargetOptions(
if (Arg *A = DriverArgs.getLastArgNoClaim(options::OPT_marm64x))
A->ignoreTargetSpecific();
}
+
+void MSVCToolChain::addMsvcstlIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+ std::string SysRoot = computeSysRoot();
+ std::string LibPath = SysRoot + "/include";
+ const std::string MultiarchTriple =
+ getMultiarchTriple(D, getTriple(), SysRoot);
+
+ std::string TargetDir = LibPath + "/" + MultiarchTriple + "/c++/msvcstl";
+ addSystemInclude(DriverArgs, CC1Args, TargetDir);
+
+ // Second add the generic one.
+ addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/msvcstl");
+}
+
+void MSVCToolChain::addLibCxxIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+ std::string SysRoot = computeSysRoot();
+ std::string LibPath = SysRoot + "/include";
+ const std::string MultiarchTriple =
+ getMultiarchTriple(D, getTriple(), SysRoot);
+
+ std::string Version = detectLibcxxVersion(LibPath);
+ if (Version.empty())
+ return;
+
+ std::string TargetDir = LibPath + "/" + MultiarchTriple + "/c++/" + Version;
+ addSystemInclude(DriverArgs, CC1Args, TargetDir);
+
+ // Second add the generic one.
+ addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/" + Version);
+}
+
+void MSVCToolChain::addLibStdCXXIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ // We cannot use GCCInstallationDetector here as the sysroot usually does
+ // not contain a full GCC installation.
+ // Instead, we search the given sysroot for /usr/include/xx, similar
+ // to how we do it for libc++.
+ const Driver &D = getDriver();
+ std::string SysRoot = computeSysRoot();
+ std::string LibPath = SysRoot + "/include";
+ const std::string MultiarchTriple =
+ getMultiarchTriple(D, getTriple(), SysRoot);
+
+ // This is similar to detectLibcxxVersion()
+ std::string Version;
+ {
+ std::error_code EC;
+ Generic_GCC::GCCVersion MaxVersion =
+ Generic_GCC::GCCVersion::Parse("0.0.0");
+ SmallString<128> Path(LibPath);
+ llvm::sys::path::append(Path, "c++");
+ for (llvm::vfs::directory_iterator LI = getVFS().dir_begin(Path, EC), LE;
+ !EC && LI != LE; LI = LI.increment(EC)) {
+ StringRef VersionText = llvm::sys::path::filename(LI->path());
+ if (VersionText[0] != 'v') {
+ auto Version = Generic_GCC::GCCVersion::Parse(VersionText);
+ if (Version > MaxVersion)
+ MaxVersion = Version;
+ }
+ }
+ if (MaxVersion.Major > 0)
+ Version = MaxVersion.Text;
+ }
+
+ if (Version.empty())
+ return;
+
+ std::string TargetDir = LibPath + "/c++/" + Version + "/" + MultiarchTriple;
+ addSystemInclude(DriverArgs, CC1Args, TargetDir);
+
+ // Second add the generic one.
+ addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/" + Version);
+ // Third the backward one.
+ addSystemInclude(DriverArgs, CC1Args,
+ LibPath + "/c++/" + Version + "/backward");
+}
diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h
index 8ff8b2815d8df..b06efdaaaca8c 100644
--- a/clang/lib/Driver/ToolChains/MSVC.h
+++ b/clang/lib/Driver/ToolChains/MSVC.h
@@ -163,6 +163,21 @@ class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain {
Tool *buildAssembler() const override;
private:
+ CXXStdlibType GetDefaultCXXStdlibType() const override {
+ return ToolChain::CST_Msvcstl;
+ }
+ RuntimeLibType GetDefaultRuntimeLibType() const override {
+ return ToolChain::RLT_Vcruntime;
+ }
+ UnwindLibType GetDefaultUnwindLibType() const override {
+ return ToolChain::UNW_Vcruntime;
+ }
+ void addMsvcstlIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+ void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+ void addLibStdCXXIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
std::optional<llvm::StringRef> WinSdkDir, WinSdkVersion, WinSysRoot;
std::string VCToolChainPath;
llvm::ToolsetLayout VSLayout = llvm::ToolsetLayout::OlderVS;
diff --git a/clang/test/Driver/msvc-sysroot.cpp b/clang/test/Driver/msvc-sysroot.cpp
new file mode 100644
index 0000000000000..32513de490df2
--- /dev/null
+++ b/clang/test/Driver/msvc-sysroot.cpp
@@ -0,0 +1,128 @@
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: split-file %s %t
+
+// --- X86_64 MSVCSTL ---
+// RUN: %clangxx --target=x86_64-unknown-windows-msvc -### \
+// RUN: --sysroot=%t/msvc_tree -fuse-ld=lld %s 2>&1 \
+// RUN: | FileCheck --check-prefix=COMPILE_X86_64_MSVCSTL %s
+// COMPILE_X86_64_MSVCSTL: clang{{.*}}" "-cc1"
+// COMPILE_X86_64_MSVCSTL: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/x86_64-unknown-windows-msvc/c++/msvcstl"
+// COMPILE_X86_64_MSVCSTL: "-internal-isystem" "[[SYSROOT]]/include/c++/msvcstl"
+// COMPILE_X86_64_MSVCSTL: "-internal-isystem" "[[SYSROOT]]{{/|\\\\}}Windows Kits{{/|\\\\}}10{{/|\\\\}}Include{{/|\\\\}}10.0.19041.0{{/|\\\\}}ucrt"
+// COMPILE_X86_64_MSVCSTL: "-internal-isystem" "[[SYSROOT]]{{/|\\\\}}VC{{/|\\\\}}Tools{{/|\\\\}}MSVC{{/|\\\\}}14.29.30133{{/|\\\\}}include"
+// COMPILE_X86_64_MSVCSTL: lld-link{{.*}}" "-libpath:[[SYSROOT]]/lib/x86_64-unknown-windows-msvc"
+// COMPILE_X86_64_MSVCSTL: "-libpath:[[SYSROOT]]{{/|\\\\}}Windows Kits{{/|\\\\}}10{{/|\\\\}}Lib{{/|\\\\}}10.0.19041.0{{/|\\\\}}ucrt{{/|\\\\}}x64"
+// COMPILE_X86_64_MSVCSTL: "-libpath:[[SYSROOT]]{{/|\\\\}}VC{{/|\\\\}}Tools{{/|\\\\}}MSVC{{/|\\\\}}14.29.30133{{/|\\\\}}lib{{/|\\\\}}x64"
+
+// --- X86_64 LIBCXX ---
+// RUN: %clangxx --target=x86_64-unknown-windows-msvc -stdlib=libc++ -### \
+// RUN: --sysroot=%t/msvc_tree -fuse-ld=lld %s 2>&1 \
+// RUN: | FileCheck --check-prefix=COMPILE_X86_64_LIBCXX %s
+// COMPILE_X86_64_LIBCXX: clang{{.*}}" "-cc1"
+// COMPILE_X86_64_LIBCXX: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/x86_64-unknown-windows-msvc/c++/v1"
+// COMPILE_X86_64_LIBCXX: "-internal-isystem" "[[SYSROOT]]/include/c++/v1"
+// COMPILE_X86_64_LIBCXX: "-internal-isystem" "[[SYSROOT]]{{/|\\\\}}Windows Kits{{/|\\\\}}10{{/|\\\\}}Include{{/|\\\\}}10.0.19041.0{{/|\\\\}}ucrt"
+// COMPILE_X86_64_LIBCXX: "-internal-isystem" "[[SYSROOT]]{{/|\\\\}}VC{{/|\\\\}}Tools{{/|\\\\}}MSVC{{/|\\\\}}14.29.30133{{/|\\\\}}include"
+// COMPILE_X86_64_LIBCXX: lld-link{{.*}}" "-libpath:[[SYSROOT]]/lib/x86_64-unknown-windows-msvc"
+// COMPILE_X86_64_LIBCXX: "-libpath:[[SYSROOT]]{{/|\\\\}}Windows Kits{{/|\\\\}}10{{/|\\\\}}Lib{{/|\\\\}}10.0.19041.0{{/|\\\\}}ucrt{{/|\\\\}}x64"
+// COMPILE_X86_64_LIBCXX: "-libpath:[[SYSROOT]]{{/|\\\\}}VC{{/|\\\\}}Tools{{/|\\\\}}MSVC{{/|\\\\}}14.29.30133{{/|\\\\}}lib{{/|\\\\}}x64"
+
+// --- X86_64 LIBSTDCXX ---
+// RUN: %clangxx -### --target=x86_64-unknown-windows-msvc --stdlib=libstdc++ %s 2>&1 \
+// RUN: -fuse-ld=lld --sysroot=%t/msvc_tree \
+// RUN: | FileCheck -check-prefix=COMPILE_X86_64_LIBSTDCXX %s
+// COMPILE_X86_64_LIBSTDCXX: "-cc1"
+// COMPILE_X86_64_LIBSTDCXX: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/c++/17.0.1/x86_64-unknown-windows-msvc"
+// COMPILE_X86_64_LIBSTDCXX: "-internal-isystem" "[[SYSROOT]]/include/c++/17.0.1"
+// COMPILE_X86_64_LIBSTDCXX: "-internal-isystem" "[[SYSROOT]]{{/|\\\\}}Windows Kits{{/|\\\\}}10{{/|\\\\}}Include{{/|\\\\}}10.0.19041.0{{/|\\\\}}ucrt"
+// COMPILE_X86_64_LIBSTDCXX: "-internal-isystem" "[[SYSROOT]]{{/|\\\\}}VC{{/|\\\\}}Tools{{/|\\\\}}MSVC{{/|\\\\}}14.29.30133{{/|\\\\}}include"
+// COMPILE_X86_64_LIBSTDCXX: lld-link{{.*}}" "-libpath:[[SYSROOT]]/lib/x86_64-unknown-windows-msvc"
+// COMPILE_X86_64_LIBSTDCXX: "-libpath:[[SYSROOT]]{{/|\\\\}}Windows Kits{{/|\\\\}}10{{/|\\\\}}Lib{{/|\\\\}}10.0.19041.0{{/|\\\\}}ucrt{{/|\\\\}}x64"
+
+// --- AARCH64 MSVCSTL ---
+// RUN: %clangxx --target=aarch64-unknown-windows-msvc -### \
+// RUN: --sysroot=%t/msvc_tree -fuse-ld=lld %s 2>&1 \
+// RUN: | FileCheck --check-prefix=COMPILE_AARCH64_MSVCSTL %s
+// COMPILE_AARCH64_MSVCSTL: clang{{.*}}" "-cc1"
+// COMPILE_AARCH64_MSVCSTL: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/aarch64-unknown-windows-msvc/c++/msvcstl"
+// COMPILE_AARCH64_MSVCSTL: "-internal-isystem" "[[SYSROOT]]/include/c++/msvcstl"
+// COMPILE_AARCH64_MSVCSTL: "-internal-isystem" "[[SYSROOT]]{{/|\\\\}}Windows Kits{{/|\\\\}}10{{/|\\\\}}Include{{/|\\\\}}10.0.19041.0{{/|\\\\}}ucrt"
+// COMPILE_AARCH64_MSVCSTL: "-internal-isystem" "[[SYSROOT]]{{/|\\\\}}VC{{/|\\\\}}Tools{{/|\\\\}}MSVC{{/|\\\\}}14.29.30133{{/|\\\\}}include"
+// COMPILE_AARCH64_MSVCSTL: lld-link{{.*}}" "-libpath:[[SYSROOT]]/lib/aarch64-unknown-windows-msvc"
+// COMPILE_AARCH64_MSVCSTL: "-libpath:[[SYSROOT]]{{/|\\\\}}Windows Kits{{/|\\\\}}10{{/|\\\\}}Lib{{/|\\\\}}10.0.19041.0{{/|\\\\}}ucrt{{/|\\\\}}arm64"
+// COMPILE_AARCH64_MSVCSTL: "-libpath:[[SYSROOT]]{{/|\\\\}}VC{{/|\\\\}}Tools{{/|\\\\}}MSVC{{/|\\\\}}14.29.30133{{/|\\\\}}lib{{/|\\\\}}arm64"
+
+// --- ARM64EC MSVCSTL ---
+// RUN: %clangxx --target=arm64ec-unknown-windows-msvc -### \
+// RUN: --sysroot=%t/msvc_tree -fuse-ld=lld %s 2>&1 \
+// RUN: | FileCheck --check-prefix=COMPILE_ARM64EC_MSVCSTL %s
+// COMPILE_ARM64EC_MSVCSTL: clang{{.*}}" "-cc1"
+// COMPILE_ARM64EC_MSVCSTL: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/arm64ec-unknown-windows-msvc/c++/msvcstl"
+// COMPILE_ARM64EC_MSVCSTL: "-internal-isystem" "[[SYSROOT]]/include/c++/msvcstl"
+// COMPILE_ARM64EC_MSVCSTL: "-internal-isystem" "[[SYSROOT]]{{/|\\\\}}Windows Kits{{/|\\\\}}10{{/|\\\\}}Include{{/|\\\\}}10.0.19041.0{{/|\\\\}}ucrt"
+// COMPILE_ARM64EC_MSVCSTL: "-internal-isystem" "[[SYSROOT]]{{/|\\\\}}VC{{/|\\\\}}Tools{{/|\\\\}}MSVC{{/|\\\\}}14.29.30133{{/|\\\\}}include"
+// COMPILE_ARM64EC_MSVCSTL: lld-link{{.*}}" "-libpath:[[SYSROOT]]/lib/arm64ec-unknown-windows-msvc" "-libpath:[[SYSROOT]]/lib/aarch64-unknown-windows-msvc"
+// COMPILE_ARM64EC_MSVCSTL: "-libpath:[[SYSROOT]]{{/|\\\\}}Windows Kits{{/|\\\\}}10{{/|\\\\}}Lib{{/|\\\\}}10.0.19041.0{{/|\\\\}}ucrt{{/|\\\\}}arm64"
+// COMPILE_ARM64EC_MSVCSTL: "-libpath:[[SYSROOT]]{{/|\\\\}}VC{{/|\\\\}}Tools{{/|\\\\}}MSVC{{/|\\\\}}14.29.30133{{/|\\\\}}lib{{/|\\\\}}arm64"
+
+// --- LOONGARCH64 MSVCSTL ---
+// RUN: %clangxx --target=loongarch64-unknown-windows-msvc -stdlib=msvcstl -### \
+// RUN: --sysroot=%t/msvc_tree -fuse-ld=lld %s 2>&1 \
+// RUN: | FileCheck --check-prefix=COMPILE_LOONGARCH64_MSVCSTL %s
+// COMPILE_LOONGARCH64_MSVCSTL: clang{{.*}}" "-cc1"
+// COMPILE_LOONGARCH64_MSVCSTL: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/loongarch64-unknown-windows-msvc/c++/msvcstl"
+// COMPILE_LOONGARCH64_MSVCSTL: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/c++/msvcstl"
+// COMPILE_LOONGARCH64_MSVCSTL: "-internal-isystem" "[[SYSROOT]]/include/loongarch64-unknown-windows-msvc"
+// COMPILE_LOONGARCH64_MSVCSTL: lld-link{{.*}}" "-libpath:[[SYSROOT]]/lib/loongarch64-unknown-windows-msvc" "-libpath:[[SYSROOT]]/lib"
+
+// --- RISCV64 LIBSTDCXX ---
+// RUN: %clangxx --target=riscv64-unknown-windows-msvc -### --stdlib=libstdc++ %s 2>&1 \
+// RUN: --sysroot=%t/msvc_tree -fuse-ld=link \
+// RUN: | FileCheck -check-prefix=COMPILE_RISCV64_LIBSTDCXX_LINK %s
+// COMPILE_RISCV64_LIBSTDCXX_LINK: "-cc1"
+// COMPILE_RISCV64_LIBSTDCXX_LINK: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/c++/17.0.1/riscv64-unknown-windows-msvc"
+// COMPILE_RISCV64_LIBSTDCXX_LINK: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/c++/17.0.1"
+// COMPILE_RISCV64_LIBSTDCXX_LINK: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/c++/17.0.1/backward"
+// COMPILE_RISCV64_LIBSTDCXX_LINK: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/riscv64-unknown-windows-msvc"
+// COMPILE_RISCV64_LIBSTDCXX_LINK: "-internal-isystem" "[[SYSROOT:[^"]+]]/include"
+// COMPILE_RISCV64_LIBSTDCXX_LINK: link.exe{{.*}}" "-libpath:[[SYSROOT]]/lib/riscv64-unknown-windows-msvc" "-libpath:[[SYSROOT]]/lib"
+
+// --- Mock Directory Structure ---
+#--- msvc_tree/VC/Tools/MSVC/14.29.30133/include/string
+#--- msvc_tree/VC/Tools/MSVC/14.29.30133/lib/x64/msvcrt.lib
+#--- msvc_tree/VC/Tools/MSVC/14.29.30133/lib/arm64/msvcrt.lib
+
+#--- msvc_tree/Windows Kits/10/Include/10.0.19041.0/ucrt/assert.h
+#--- msvc_tree/Windows Kits/10/Lib/10.0.19041.0/ucrt/x64/ucrt.lib
+#--- msvc_tree/Windows Kits/10/Lib/10.0.19041.0/ucrt/arm64/ucrt.lib
+
+
+#--- msvc_tree/include/c++/msvcstl/string
+#--- msvc_tree/include/c++/v1/string
+#--- msvc_tree/include/c++/17.0.1/string
+#--- msvc_tree/include/x86_64-unknown-windows-msvc/c++/msvcstl/string
+#--- msvc_tree/include/aarch64-unknown-windows-msvc/c++/msvcstl/string
+#--- msvc_tree/include/loongarch64-unknown-windows-msvc/c++/msvcstl/string
+#--- msvc_tree/include/riscv64-unknown-windows-msvc/c++/msvcstl/string
+#--- msvc_tree/include/x86_64-unknown-windows-msvc/c++/v1/string
+#--- msvc_tree/include/aarch64-unknown-windows-msvc/c++/v1/string
+#--- msvc_tree/include/loongarch64-unknown-windows-msvc/c++/v1/string
+#--- msvc_tree/include/riscv64-unknown-windows-msvc/c++/v1/string
+#--- msvc_tree/include/x86_64-unknown-windows-msvc/c++/17.0.1/string
+#--- msvc_tree/include/aarch64-unknown-windows-msvc/c++/17.0.1/string
+#--- msvc_tree/include/loongarch64-unknown-windows-msvc/c++/17.0.1/string
+#--- msvc_tree/include/riscv64-unknown-windows-msvc/c++/17.0.1/string
+#--- msvc_tree/include/c++/17.0.1/x86_64-unknown-windows-msvc/string
+#--- msvc_tree/include/c++/17.0.1/aarch64-unknown-windows-msvc/string
+#--- msvc_tree/include/c++/17.0.1/loongarch64-unknown-windows-msvc/string
+#--- msvc_tree/include/c++/17.0.1/riscv64-unknown-windows-msvc/string
+
+#--- msvc_tree/include/riscv64-unknown-windows-msvc/empty
+#--- msvc_tree/lib/x86_64-unknown-windows-msvc/empty
+#--- msvc_tree/lib/aarch64-unknown-windows-msvc/empty
+#--- msvc_tree/lib/loongarch64-unknown-windows-msvc/empty
+#--- msvc_tree/lib/riscv64-unknown-windows-msvc/empty
+#--- msvc_tree/lib/empty
+
+#--- foo.cpp
+int main() { return 0; }
\ No newline at end of file
>From 39ae3a796ed945bd466c09b0819a6d966218a924 Mon Sep 17 00:00:00 2001
From: trcrsired <oyzawqgcfc at gmail.com>
Date: Thu, 20 Aug 2026 18:41:27 +0800
Subject: [PATCH 02/10] [skip ci] Try to reimplement
--print-cxx-stdlib-include-dirs
Upstream code does not add a specific virtual method for
this feature which makes rewriting hard.
First backup code here so i can build or i will lose code
---
clang/include/clang/Driver/ToolChain.h | 4 +++
clang/lib/Driver/Driver.cpp | 17 ++----------
clang/lib/Driver/ToolChain.cpp | 38 ++++++++++++++++++++++++++
clang/lib/Driver/ToolChains/MSVC.cpp | 23 ++++++++++++++++
clang/lib/Driver/ToolChains/MSVC.h | 2 ++
5 files changed, 69 insertions(+), 15 deletions(-)
diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h
index d1db6e7ba1cee..be00dfcceced8 100644
--- a/clang/include/clang/Driver/ToolChain.h
+++ b/clang/include/clang/Driver/ToolChain.h
@@ -293,6 +293,10 @@ class ToolChain {
/// GPUs.
virtual std::string getInputFilename(const InputInfo &Input) const;
+ /// for printing C++ standard library include dirs
+ virtual llvm::SmallVector<std::string>
+ getCXXStdlibIncludeDirs(const llvm::opt::ArgList &DriverArgs) const;
+
llvm::Triple::ArchType getArch() const { return Triple.getArch(); }
StringRef getArchName() const { return Triple.getArchName(); }
StringRef getPlatform() const { return Triple.getVendorName(); }
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 50a6893fbbe1a..7684f2b9a2dda 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -136,23 +136,10 @@ template <typename F> static bool usesInput(const ArgList &Args, F &&Fn) {
});
}
-static bool isIncludeDirArg(StringRef Arg) {
- return Arg == "-internal-isystem" || Arg == "-internal-externc-isystem" ||
- Arg == "-isystem" || Arg == "-cxx-isystem" || Arg == "-idirafter";
-}
-
static void printCXXStdlibIncludeDirs(const ToolChain &TC,
const ArgList &Args) {
- ArgStringList CC1Args;
- if (Args.hasArg(options::OPT_stdlibxx_isystem))
- TC.AddClangCXXStdlibIsystemArgs(Args, CC1Args);
- else
- TC.AddClangCXXStdlibIncludeArgs(Args, CC1Args);
-
- for (size_t I = 0; I < CC1Args.size(); ++I) {
- StringRef Arg(CC1Args[I]);
- if (isIncludeDirArg(Arg) && I + 1 < CC1Args.size())
- llvm::outs() << CC1Args[++I] << '\n';
+ for (const auto &str : TC.getCXXStdlibIncludeDirs(Args)) {
+ llvm::outs() << str << '\n';
}
}
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 85201ec2baa40..1450b25e7a6a3 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -702,6 +702,44 @@ std::string ToolChain::getInputFilename(const InputInfo &Input) const {
return Input.getFilename();
}
+static bool isIncludeDirArg(StringRef Arg) {
+ return Arg == "-internal-isystem" || Arg == "-internal-externc-isystem" ||
+ Arg == "-isystem" || Arg == "-cxx-isystem" || Arg == "-idirafter";
+}
+
+static std::string printCXXStdlibIncludeDirs(const ToolChain &TC,
+ const ArgList &Args) {
+ ArgStringList CC1Args;
+ if (Args.hasArg(options::OPT_stdlibxx_isystem))
+ TC.AddClangCXXStdlibIsystemArgs(Args, CC1Args);
+ else
+ TC.AddClangCXXStdlibIncludeArgs(Args, CC1Args);
+
+ for (size_t I = 0; I < CC1Args.size(); ++I) {
+ StringRef Arg(CC1Args[I]);
+ if (isIncludeDirArg(Arg) && I + 1 < CC1Args.size())
+ llvm::outs() << CC1Args[++I] << '\n';
+ }
+}
+
+llvm::SmallVector<std::string>
+getCXXStdlibIncludeDirs(const ArgList &Args) const {
+ ArgStringList CC1Args;
+ if (Args.hasArg(options::OPT_stdlibxx_isystem))
+ TempTC.AddClangCXXStdlibIsystemArgs(Args, CC1Args);
+ else
+ TempTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args);
+
+ llvm::SmallVector<std::string> Args;
+ for (size_t I = 0; I < CC1Args.size(); ++I) {
+ StringRef Arg(CC1Args[I]);
+ if (isIncludeDirArg(Arg) && I + 1 < CC1Args.size()) {
+ Args.emplace_back(CC1Args[++I]);
+ }
+ }
+ return Args;
+}
+
ToolChain::UnwindTableLevel
ToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const {
return UnwindTableLevel::None;
diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp
index 66afdb6213db4..4c882171702ef 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -1439,3 +1439,26 @@ void MSVCToolChain::addLibStdCXXIncludePaths(
addSystemInclude(DriverArgs, CC1Args,
LibPath + "/c++/" + Version + "/backward");
}
+
+llvm::SmallVector<std::string> MSVCToolChain::getCXXStdlibIncludeDirs(
+ const llvm::opt::ArgList &DriverArgs) const {
+ auto cxxStdlibType = GetCXXStdlibType(DriverArgs);
+ if (cxxStdlibType == ToolChain::CST_Msvcstl) {
+ std::string includePaths;
+ auto SysRoot = TC.getDriver().SysRoot;
+ if (Sysroot.empty()) {
+ if (!VCToolChainPath.empty()) {
+ includePaths.push_back(VCToolChainPath.getSubDirectoryPath(
+ llvm::SubDirectoryType::Include));
+ }
+ } else {
+ std::string VCToolsBase = SysRoot + "/VC/Tools/MSVC";
+ std::string VCVer = getHighestVersion(VFS, VCToolsBase);
+ if (!VCVer.empty()) {
+ vec.push_back(VCToolsBase + "/" + VCVer + "/include");
+ }
+ }
+ return vec;
+ }
+ return Toolchain::getCXXStdlibIncludeDirs(DriverArgs);
+}
diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h
index b06efdaaaca8c..207551936923d 100644
--- a/clang/lib/Driver/ToolChains/MSVC.h
+++ b/clang/lib/Driver/ToolChains/MSVC.h
@@ -161,6 +161,8 @@ class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain {
Tool *getTool(Action::ActionClass AC) const override;
Tool *buildLinker() const override;
Tool *buildAssembler() const override;
+ llvm::SmallVector<std::string>
+ getCXXStdlibIncludeDirs(const llvm::opt::ArgList &DriverArgs) const override;
private:
CXXStdlibType GetDefaultCXXStdlibType() const override {
>From e36286457d207d69305c823b6726079f6d61e216 Mon Sep 17 00:00:00 2001
From: trcrsired <oyzawqgcfc at gmail.com>
Date: Thu, 20 Aug 2026 22:04:52 +0800
Subject: [PATCH 03/10] [skip ci][clang] make the compilation pass first.
i will deal with the issue later
---
clang/lib/Driver/ToolChain.cpp | 12 ++++++------
clang/lib/Driver/ToolChains/MSVC.cpp | 11 +++++++----
2 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 1450b25e7a6a3..c7c8f13b8f5f7 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -723,21 +723,21 @@ static std::string printCXXStdlibIncludeDirs(const ToolChain &TC,
}
llvm::SmallVector<std::string>
-getCXXStdlibIncludeDirs(const ArgList &Args) const {
+ToolChain::getCXXStdlibIncludeDirs(const ArgList &Args) const {
ArgStringList CC1Args;
if (Args.hasArg(options::OPT_stdlibxx_isystem))
- TempTC.AddClangCXXStdlibIsystemArgs(Args, CC1Args);
+ AddClangCXXStdlibIsystemArgs(Args, CC1Args);
else
- TempTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args);
+ AddClangCXXStdlibIncludeArgs(Args, CC1Args);
- llvm::SmallVector<std::string> Args;
+ llvm::SmallVector<std::string> Rets;
for (size_t I = 0; I < CC1Args.size(); ++I) {
StringRef Arg(CC1Args[I]);
if (isIncludeDirArg(Arg) && I + 1 < CC1Args.size()) {
- Args.emplace_back(CC1Args[++I]);
+ Rets.emplace_back(CC1Args[++I]);
}
}
- return Args;
+ return Rets;
}
ToolChain::UnwindTableLevel
diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp
index 4c882171702ef..1a99501ad3ffe 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -1444,21 +1444,24 @@ llvm::SmallVector<std::string> MSVCToolChain::getCXXStdlibIncludeDirs(
const llvm::opt::ArgList &DriverArgs) const {
auto cxxStdlibType = GetCXXStdlibType(DriverArgs);
if (cxxStdlibType == ToolChain::CST_Msvcstl) {
+ llvm::SmallVector<std::string> vec;
std::string includePaths;
- auto SysRoot = TC.getDriver().SysRoot;
- if (Sysroot.empty()) {
+ auto SysRoot = getDriver().SysRoot;
+ if (SysRoot.empty()) {
if (!VCToolChainPath.empty()) {
+#if 0
includePaths.push_back(VCToolChainPath.getSubDirectoryPath(
llvm::SubDirectoryType::Include));
+#endif
}
} else {
std::string VCToolsBase = SysRoot + "/VC/Tools/MSVC";
- std::string VCVer = getHighestVersion(VFS, VCToolsBase);
+ std::string VCVer = getHighestVersion(getVFS(), VCToolsBase);
if (!VCVer.empty()) {
vec.push_back(VCToolsBase + "/" + VCVer + "/include");
}
}
return vec;
}
- return Toolchain::getCXXStdlibIncludeDirs(DriverArgs);
+ return ToolChain::getCXXStdlibIncludeDirs(DriverArgs);
}
>From 584c8f6bef6d8a49d1b823ce54671b395c8c15a2 Mon Sep 17 00:00:00 2001
From: trcrsired <oyzawqgcfc at gmail.com>
Date: Fri, 21 Aug 2026 01:58:56 +0800
Subject: [PATCH 04/10] [skip ci][clang] Correctly implement MSVC's
getCXXStdlibIncludeDirs
I will add test later on
---
clang/lib/Driver/ToolChains/MSVC.cpp | 31 +++++++++++++++++++---------
clang/lib/Driver/ToolChains/MSVC.h | 3 +--
2 files changed, 22 insertions(+), 12 deletions(-)
diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp
index 1a99501ad3ffe..5a91a6a7435f3 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -173,6 +173,8 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// libpath is $SYSROOT/lib and $SYSROOT/lib/${ARCH}-unknown-windows-msvc
// For ARM64EC, the ARCH is aarch64 instead
auto triple = TC.getTriple();
+ // always set vendor to unknown to ensure consistency
+ triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
const std::string MultiarchTriple =
TC.getMultiarchTriple(TC.getDriver(), triple, SysRoot);
std::string SysRootLib = "-libpath:" + SysRoot + "/lib";
@@ -1363,8 +1365,10 @@ void MSVCToolChain::addMsvcstlIncludePaths(
const Driver &D = getDriver();
std::string SysRoot = computeSysRoot();
std::string LibPath = SysRoot + "/include";
- const std::string MultiarchTriple =
- getMultiarchTriple(D, getTriple(), SysRoot);
+ auto triple = getTriple();
+ // always set vendor to unknown to ensure consistency
+ triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
+ const std::string MultiarchTriple = getMultiarchTriple(D, triple, SysRoot);
std::string TargetDir = LibPath + "/" + MultiarchTriple + "/c++/msvcstl";
addSystemInclude(DriverArgs, CC1Args, TargetDir);
@@ -1449,16 +1453,23 @@ llvm::SmallVector<std::string> MSVCToolChain::getCXXStdlibIncludeDirs(
auto SysRoot = getDriver().SysRoot;
if (SysRoot.empty()) {
if (!VCToolChainPath.empty()) {
-#if 0
- includePaths.push_back(VCToolChainPath.getSubDirectoryPath(
- llvm::SubDirectoryType::Include));
-#endif
+ vec.push_back(getSubDirectoryPath(llvm::SubDirectoryType::Include));
}
} else {
- std::string VCToolsBase = SysRoot + "/VC/Tools/MSVC";
- std::string VCVer = getHighestVersion(getVFS(), VCToolsBase);
- if (!VCVer.empty()) {
- vec.push_back(VCToolsBase + "/" + VCVer + "/include");
+ // First trying to get from sysroot
+ auto &VFS = getVFS();
+ std::string WinKitsBase = SysRoot + "/Windows Kits";
+ if (VFS.exists(WinKitsBase)) {
+ std::string VCToolsBase = SysRoot + "/VC/Tools/MSVC";
+ std::string VCVer = getHighestVersion(getVFS(), VCToolsBase);
+ if (!VCVer.empty()) {
+ vec.push_back(VCToolsBase + "/" + VCVer + "/include");
+ }
+ }
+ // ensure the correct order
+ auto UnixSysRootResults = ToolChain::getCXXStdlibIncludeDirs(DriverArgs);
+ for (auto &e : UnixSysRootResults) {
+ vec.push_back(::std::move(e));
}
}
return vec;
diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h
index 207551936923d..aca2bad9da514 100644
--- a/clang/lib/Driver/ToolChains/MSVC.h
+++ b/clang/lib/Driver/ToolChains/MSVC.h
@@ -101,8 +101,7 @@ class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain {
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
- llvm::StringRef
- GetCXXStdlibName(const llvm::opt::ArgList &DriverArgs) const override;
+
void AddClangCXXStdlibIncludeArgs(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
>From 0502fb138d89964cf7dd73367572b5459a7da9b9 Mon Sep 17 00:00:00 2001
From: trcrsired <oyzawqgcfc at gmail.com>
Date: Fri, 21 Aug 2026 02:36:19 +0800
Subject: [PATCH 05/10] [skip ci][clang] move unknown triple into a function
---
clang/lib/Driver/ToolChains/MSVC.cpp | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp
index 5a91a6a7435f3..45ab10dc12f20 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -87,6 +87,13 @@ static std::string getHighestVersion(llvm::vfs::FileSystem &VFS,
return HighestVersion;
}
+// always set vendor to unknown to ensure consistency for sysroot
+static llvm::Triple getTripleWithUnknownVendor(const ToolChain &TC) {
+ auto triple = TC.getTriple();
+ triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
+ return triple;
+}
+
void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -172,9 +179,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// If we have --sysroot, then we ignore all other setings
// libpath is $SYSROOT/lib and $SYSROOT/lib/${ARCH}-unknown-windows-msvc
// For ARM64EC, the ARCH is aarch64 instead
- auto triple = TC.getTriple();
- // always set vendor to unknown to ensure consistency
- triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
+ auto triple = getTripleWithUnknownVendor(TC);
const std::string MultiarchTriple =
TC.getMultiarchTriple(TC.getDriver(), triple, SysRoot);
std::string SysRootLib = "-libpath:" + SysRoot + "/lib";
@@ -1365,10 +1370,8 @@ void MSVCToolChain::addMsvcstlIncludePaths(
const Driver &D = getDriver();
std::string SysRoot = computeSysRoot();
std::string LibPath = SysRoot + "/include";
- auto triple = getTriple();
- // always set vendor to unknown to ensure consistency
- triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
- const std::string MultiarchTriple = getMultiarchTriple(D, triple, SysRoot);
+ const std::string MultiarchTriple =
+ getMultiarchTriple(D, getTripleWithUnknownVendor(*this), SysRoot);
std::string TargetDir = LibPath + "/" + MultiarchTriple + "/c++/msvcstl";
addSystemInclude(DriverArgs, CC1Args, TargetDir);
@@ -1384,7 +1387,7 @@ void MSVCToolChain::addLibCxxIncludePaths(
std::string SysRoot = computeSysRoot();
std::string LibPath = SysRoot + "/include";
const std::string MultiarchTriple =
- getMultiarchTriple(D, getTriple(), SysRoot);
+ getMultiarchTriple(D, getTripleWithUnknownVendor(*this), SysRoot);
std::string Version = detectLibcxxVersion(LibPath);
if (Version.empty())
@@ -1408,7 +1411,7 @@ void MSVCToolChain::addLibStdCXXIncludePaths(
std::string SysRoot = computeSysRoot();
std::string LibPath = SysRoot + "/include";
const std::string MultiarchTriple =
- getMultiarchTriple(D, getTriple(), SysRoot);
+ getMultiarchTriple(D, getTripleWithUnknownVendor(*this), SysRoot);
// This is similar to detectLibcxxVersion()
std::string Version;
>From f706a8f0c51e14d41505aa54a48e9a7078c54fe3 Mon Sep 17 00:00:00 2001
From: trcrsired <oyzawqgcfc at gmail.com>
Date: Fri, 21 Aug 2026 04:02:50 +0800
Subject: [PATCH 06/10] [clang] Try to add back all the break to see whether ci
passes
The requirement by some reviewers on ignoring the switch
is completely false since it breaks CI
---
clang/lib/Driver/ToolChain.cpp | 15 ----------
clang/lib/Driver/ToolChains/AIX.cpp | 6 ++--
clang/lib/Driver/ToolChains/BareMetal.cpp | 11 +++++++
clang/lib/Driver/ToolChains/CommonArgs.cpp | 3 ++
clang/lib/Driver/ToolChains/Darwin.cpp | 5 ++++
clang/lib/Driver/ToolChains/Fuchsia.cpp | 1 +
clang/lib/Driver/ToolChains/Gnu.cpp | 2 ++
clang/lib/Driver/ToolChains/MinGW.cpp | 4 +++
clang/lib/Driver/ToolChains/OHOS.cpp | 1 +
clang/lib/Driver/ToolChains/WebAssembly.cpp | 4 +++
clang/lib/Driver/ToolChains/ZOS.cpp | 3 +-
clang/test/Driver/msvc-sysroot.cpp | 33 +++++++++++++++++++++
12 files changed, 70 insertions(+), 18 deletions(-)
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 437686ce7f40e..c1cd8c16f3254 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -708,21 +708,6 @@ static bool isIncludeDirArg(StringRef Arg) {
Arg == "-isystem" || Arg == "-cxx-isystem" || Arg == "-idirafter";
}
-static std::string printCXXStdlibIncludeDirs(const ToolChain &TC,
- const ArgList &Args) {
- ArgStringList CC1Args;
- if (Args.hasArg(options::OPT_stdlibxx_isystem))
- TC.AddClangCXXStdlibIsystemArgs(Args, CC1Args);
- else
- TC.AddClangCXXStdlibIncludeArgs(Args, CC1Args);
-
- for (size_t I = 0; I < CC1Args.size(); ++I) {
- StringRef Arg(CC1Args[I]);
- if (isIncludeDirArg(Arg) && I + 1 < CC1Args.size())
- llvm::outs() << CC1Args[++I] << '\n';
- }
-}
-
llvm::SmallVector<std::string>
ToolChain::getCXXStdlibIncludeDirs(const ArgList &Args) const {
ArgStringList CC1Args;
diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp
index 586bc08067eff..f80433a5ef521 100644
--- a/clang/lib/Driver/ToolChains/AIX.cpp
+++ b/clang/lib/Driver/ToolChains/AIX.cpp
@@ -433,8 +433,9 @@ void AIX::AddClangCXXStdlibIncludeArgs(
switch (GetCXXStdlibType(DriverArgs)) {
case ToolChain::CST_Libstdcxx:
+ case ToolChain::CST_Msvcstl:
llvm::report_fatal_error(
- "picking up libstdc++ headers is unimplemented on AIX");
+ "picking up non-libc++ headers is unimplemented on AIX");
case ToolChain::CST_Libcxx: {
llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs);
SmallString<128> PathCPP(Sysroot);
@@ -468,7 +469,8 @@ void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const {
switch (GetCXXStdlibType(Args)) {
case ToolChain::CST_Libstdcxx:
- llvm::report_fatal_error("linking libstdc++ unimplemented on AIX");
+ case ToolChain::CST_Msvcstl:
+ llvm::report_fatal_error("linking non-libc++ unimplemented on AIX");
case ToolChain::CST_Libcxx:
CmdArgs.push_back("-lc++");
if (Args.hasArg(options::OPT_fexperimental_library))
diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp
index ba454acbf755c..4b9fcccfbc78a 100644
--- a/clang/lib/Driver/ToolChains/BareMetal.cpp
+++ b/clang/lib/Driver/ToolChains/BareMetal.cpp
@@ -408,6 +408,10 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
case ToolChain::CST_Libstdcxx:
addLibStdCxxIncludePaths(DriverArgs, CC1Args);
break;
+ case ToolChain::CST_Msvcstl:
+ llvm::report_fatal_error(
+ "picking up MSVC STL headers is unimplemented on AIX");
+ break;
}
std::string SysRootDir(computeSysRoot());
@@ -454,6 +458,9 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
}
break;
}
+ case ToolChain::CST_Msvcstl: {
+ break;
+ }
}
}
switch (GetCXXStdlibType(DriverArgs)) {
@@ -465,6 +472,7 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
break;
}
case ToolChain::CST_Libstdcxx:
+ case ToolChain::CST_Msvcstl:
break;
}
}
@@ -587,6 +595,9 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
TC.getCompilerRTArgString(Args, "crtend", ToolChain::FT_Object);
break;
}
+ case (ToolChain::RTL_Vcruntime) {
+ break;
+ }
}
CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(CRTBegin)));
}
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 74e27bf8b9cde..c05420a282e31 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -2505,6 +2505,7 @@ static void AddUnwindLibrary(const ToolChain &TC, const Driver &D,
switch (UNW) {
case ToolChain::UNW_None:
+ case ToolChain::UNW_Vcruntime:
return;
case ToolChain::UNW_Libgcc: {
if (LGT == LibGccType::StaticLibGcc)
@@ -2580,6 +2581,8 @@ void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D,
} else
AddLibgcc(TC, D, CmdArgs, Args);
break;
+ case ToolChain::RLT_Vcruntime:
+ break;
}
// On Android, the unwinder uses dl_iterate_phdr (or one of
diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp
index d3de04fc5155e..6c670453099ce 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -3038,6 +3038,8 @@ void AppleMachO::AddClangCXXStdlibIncludeArgs(
case ToolChain::CST_Libstdcxx:
AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args);
break;
+ case ToolChain::CST_Msvcstl:
+ break;
}
}
@@ -3133,6 +3135,9 @@ void AppleMachO::AddCXXStdlibLibArgs(const ArgList &Args,
CmdArgs.push_back("-lstdc++");
break;
}
+case ToolChain::CST_Msvcstl: {
+ break;
+}
}
void DarwinClang::AddCCKextLibArgs(const ArgList &Args,
diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp
index abde9fa10482d..dcf813c5b035f 100644
--- a/clang/lib/Driver/ToolChains/Fuchsia.cpp
+++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp
@@ -468,6 +468,7 @@ void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args,
break;
case ToolChain::CST_Libstdcxx:
+ case ToolChain::CST_Msvcstl:
llvm_unreachable("invalid stdlib name");
}
}
diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index 72affac131701..98370d851480a 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -3245,6 +3245,8 @@ void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
case ToolChain::CST_Libstdcxx:
addLibStdCxxIncludePaths(DriverArgs, CC1Args);
break;
+ case ToolChain::CST_Msvcstl:
+ break;
}
}
diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp
index 65120931d8181..04988998fa8fd 100644
--- a/clang/lib/Driver/ToolChains/MinGW.cpp
+++ b/clang/lib/Driver/ToolChains/MinGW.cpp
@@ -823,6 +823,10 @@ void toolchains::MinGW::AddClangCXXStdlibIncludeArgs(
StringRef Slash = llvm::sys::path::get_separator();
switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Msvcstl: {
+ llvm::report_fatal_error("picking up MSVC STL headers is unimplemented");
+ break;
+ }
case ToolChain::CST_Libcxx: {
std::string TargetDir = (Base + "include" + Slash + getTripleString() +
Slash + "c++" + Slash + "v1")
diff --git a/clang/lib/Driver/ToolChains/OHOS.cpp b/clang/lib/Driver/ToolChains/OHOS.cpp
index dda00c9250a5f..60ec64e69b7b0 100644
--- a/clang/lib/Driver/ToolChains/OHOS.cpp
+++ b/clang/lib/Driver/ToolChains/OHOS.cpp
@@ -267,6 +267,7 @@ void OHOS::AddCXXStdlibLibArgs(const ArgList &Args,
break;
case ToolChain::CST_Libstdcxx:
+ case ToolChain::CST_Msvcstl:
llvm_unreachable("invalid stdlib name");
}
}
diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp
index 7d5d406df2399..9315b2d04f2d5 100644
--- a/clang/lib/Driver/ToolChains/WebAssembly.cpp
+++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp
@@ -567,6 +567,8 @@ void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
case ToolChain::CST_Libstdcxx:
addLibStdCXXIncludePaths(DriverArgs, CC1Args);
break;
+ case ToolChain::CST_Msvcstl:
+ llvm::report_fatal_error("picking up MSVC STL headers is unimplemented");
}
}
@@ -583,6 +585,8 @@ void WebAssembly::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
case ToolChain::CST_Libstdcxx:
CmdArgs.push_back("-lstdc++");
break;
+ case ToolChain::CST_Msvcstl:
+ break;
}
}
diff --git a/clang/lib/Driver/ToolChains/ZOS.cpp b/clang/lib/Driver/ToolChains/ZOS.cpp
index da4aaa28cd1da..6ffc1ff013258 100644
--- a/clang/lib/Driver/ToolChains/ZOS.cpp
+++ b/clang/lib/Driver/ToolChains/ZOS.cpp
@@ -244,7 +244,8 @@ void ZOS::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const {
switch (GetCXXStdlibType(Args)) {
case ToolChain::CST_Libstdcxx:
- llvm::report_fatal_error("linking libstdc++ is unimplemented on z/OS");
+ case ToolChain::CST_Msvcstl:
+ llvm::report_fatal_error("linking non libc++ is unimplemented on z/OS");
break;
case ToolChain::CST_Libcxx: {
std::string ClangHLQ = getClangHLQ(Args);
diff --git a/clang/test/Driver/msvc-sysroot.cpp b/clang/test/Driver/msvc-sysroot.cpp
index 32513de490df2..cc50b61665266 100644
--- a/clang/test/Driver/msvc-sysroot.cpp
+++ b/clang/test/Driver/msvc-sysroot.cpp
@@ -87,6 +87,39 @@
// COMPILE_RISCV64_LIBSTDCXX_LINK: "-internal-isystem" "[[SYSROOT:[^"]+]]/include"
// COMPILE_RISCV64_LIBSTDCXX_LINK: link.exe{{.*}}" "-libpath:[[SYSROOT]]/lib/riscv64-unknown-windows-msvc" "-libpath:[[SYSROOT]]/lib"
+// --- AARCH64 print-cxx-stdlib MSVCSTL ---
+// RUN: %clangxx --target=aarch64-unknown-windows-msvc --print-cxx-stdlib \
+// RUN: --sysroot=%t/msvc_tree %s 2>&1 \
+// RUN: | FileCheck --check-prefix=PRINTCXXSTDLIB_AARCH64_MSVCSTL %s
+// PRINTCXXSTDLIB_AARCH64_MSVCSTL: msvcstl
+
+// --- X86_64 print-cxx-stdlib LIBCXX ---
+// RUN: %clangxx --target=x86_64-unknown-windows-msvc -stdlib=libc++ --print-cxx-stdlib \
+// RUN: --sysroot=%t/msvc_tree %s 2>&1 \
+// RUN: | FileCheck --check-prefix=PRINTCXXSTDLIB_X86_64_LIBCXX %s
+// PRINTCXXSTDLIB_X86_64_LIBCXX: libc++
+
+// --- LOONGARCH64 print-cxx-stdlib LIBSTDCXX ---
+// RUN: %clangxx --target=loongarch64-unknown-windows-msvc -stdlib=libstdc++ --print-cxx-stdlib \
+// RUN: --sysroot=%t/msvc_tree %s 2>&1 \
+// RUN: | FileCheck --check-prefix=PRINTCXXSTDLIB_LOONGARCH64_LIBSTDCXX %s
+// PRINTCXXSTDLIB_LOONGARCH64_LIBSTDCXX: libstdc++
+
+// --- X86_64 print-cxx-stdlib-include-dirs MSVCSTL ---
+// RUN: %clangxx --target=x86_64-unknown-windows-msvc --print-cxx-stdlib-include-dirs -stdlib=libc++ \
+// RUN: --sysroot=%t/msvc_tree 2>&1 \
+// RUN: | FileCheck --check-prefix=PRINTCXXSTDLIBINCLUDE_X86_64_LIBCXX %s
+// PRINTCXXSTDLIBINCLUDE_X86_64_LIBCXX: [[SYSROOT:[^"]+]]/include/x86_64-unknown-windows-msvc/c++/v1
+// PRINTCXXSTDLIBINCLUDE_X86_64_LIBCXX: [[SYSROOT:[^"]+]]/include/c++/v1
+
+// --- AARCH64 print-cxx-stdlib-include-dirs MSVCSTL ---
+// RUN: %clangxx --target=aarch64-unknown-windows-msvc --print-cxx-stdlib-include-dirs \
+// RUN: --sysroot=%t/msvc_tree 2>&1 \
+// RUN: | FileCheck --check-prefix=PRINTCXXSTDLIB_AARCH64_MSVCSTL %s
+// PRINTCXXSTDLIBINCLUDE_AARCH64_MSVCSTL: [[SYSROOT:[^"]+]]/include/aarch64-unknown-windows-msvc/c++/msvcstl
+// PRINTCXXSTDLIBINCLUDE_AARCH64_MSVCSTL: [[SYSROOT:[^"]+]]/include/c++/msvcstl
+// PRINTCXXSTDLIBINCLUDE_AARCH64_MSVCSTL: [[SYSROOT:[^"]+]]/VC/Tools/MSVC/14.29.30133/include
+
// --- Mock Directory Structure ---
#--- msvc_tree/VC/Tools/MSVC/14.29.30133/include/string
#--- msvc_tree/VC/Tools/MSVC/14.29.30133/lib/x64/msvcrt.lib
>From 9685a250e7d7e31c047876d6cb5b6fa52c0d7128 Mon Sep 17 00:00:00 2001
From: trcrsired <oyzawqgcfc at gmail.com>
Date: Fri, 21 Aug 2026 04:17:47 +0800
Subject: [PATCH 07/10] [clang] build issues due for losing frontnd ignores
---
clang/lib/Driver/ToolChains/BareMetal.cpp | 2 +-
clang/lib/Driver/ToolChains/Hexagon.cpp | 3 +++
clang/lib/Driver/ToolChains/ZOS.cpp | 1 +
3 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp
index 4b9fcccfbc78a..de99c0bcef73d 100644
--- a/clang/lib/Driver/ToolChains/BareMetal.cpp
+++ b/clang/lib/Driver/ToolChains/BareMetal.cpp
@@ -595,7 +595,7 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
TC.getCompilerRTArgString(Args, "crtend", ToolChain::FT_Object);
break;
}
- case (ToolChain::RTL_Vcruntime) {
+ case (ToolChain::RLT_Vcruntime) {
break;
}
}
diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp
index 76c5cafd77bc9..e87a295befdd0 100644
--- a/clang/lib/Driver/ToolChains/Hexagon.cpp
+++ b/clang/lib/Driver/ToolChains/Hexagon.cpp
@@ -806,6 +806,9 @@ void HexagonToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
case ToolChain::CST_Libstdcxx:
CmdArgs.push_back("-lstdc++");
break;
+ case ToolChain::CST_Msvcstl:
+ llvm::report_fatal_error("linking msvcstl is unimplemented");
+ break;
}
}
diff --git a/clang/lib/Driver/ToolChains/ZOS.cpp b/clang/lib/Driver/ToolChains/ZOS.cpp
index 6ffc1ff013258..975f4375fb66c 100644
--- a/clang/lib/Driver/ToolChains/ZOS.cpp
+++ b/clang/lib/Driver/ToolChains/ZOS.cpp
@@ -356,6 +356,7 @@ void ZOS::AddClangCXXStdlibIncludeArgs(
break;
}
case ToolChain::CST_Libstdcxx:
+ case ToolChain::CST_Msvcstl:
llvm::report_fatal_error(
"picking up libstdc++ headers is unimplemented on z/OS");
break;
>From 81a0d04f6d37ef8031902c63f5f7d1c3b0fca89b Mon Sep 17 00:00:00 2001
From: trcrsired <oyzawqgcfc at gmail.com>
Date: Fri, 21 Aug 2026 04:37:22 +0800
Subject: [PATCH 08/10] [clang] Other two compilation errors for -Werror
bypassing resolved. to see whether we have more
---
clang/lib/Driver/ToolChains/BareMetal.cpp | 2 +-
clang/lib/Driver/ToolChains/Darwin.cpp | 5 ++---
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp
index de99c0bcef73d..3701c2cd5d062 100644
--- a/clang/lib/Driver/ToolChains/BareMetal.cpp
+++ b/clang/lib/Driver/ToolChains/BareMetal.cpp
@@ -595,7 +595,7 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
TC.getCompilerRTArgString(Args, "crtend", ToolChain::FT_Object);
break;
}
- case (ToolChain::RLT_Vcruntime) {
+ case (ToolChain::RLT_Vcruntime): {
break;
}
}
diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp
index 6c670453099ce..d18fe6b71e2f4 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -3134,10 +3134,9 @@ void AppleMachO::AddCXXStdlibLibArgs(const ArgList &Args,
// Otherwise, let the linker search.
CmdArgs.push_back("-lstdc++");
break;
+ case ToolChain::CST_Msvcstl:
+ break;
}
-case ToolChain::CST_Msvcstl: {
- break;
-}
}
void DarwinClang::AddCCKextLibArgs(const ArgList &Args,
>From c7945826f545c8b18f8b21a09f68a2ed62598c70 Mon Sep 17 00:00:00 2001
From: trcrsired <oyzawqgcfc at gmail.com>
Date: Fri, 21 Aug 2026 04:50:59 +0800
Subject: [PATCH 09/10] [clang]Baremetal one case has uninitialized varible
that the Msvcstl enum introduces
---
clang/lib/Driver/ToolChains/BareMetal.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp
index 3701c2cd5d062..c02d821bdc269 100644
--- a/clang/lib/Driver/ToolChains/BareMetal.cpp
+++ b/clang/lib/Driver/ToolChains/BareMetal.cpp
@@ -572,7 +572,7 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
bool NeedCRTs =
!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles);
- const char *CRTBegin, *CRTEnd;
+ const char *CRTBegin = nullptr, *CRTEnd = nullptr;
if (NeedCRTs) {
if (!Args.hasArg(options::OPT_r)) {
const char *crt = "crt0.o";
>From 4f91c2c339421dc347d2eeeb33c155e8ed91a49e Mon Sep 17 00:00:00 2001
From: trcrsired <oyzawqgcfc at gmail.com>
Date: Fri, 21 Aug 2026 11:52:00 +0800
Subject: [PATCH 10/10] [clang] aix toolchain-include should have non-libc++
rather than hardcoded libstdc++ for that case
--print-cxx-stdlib-include-dirs for msvc should not have
MSVC STL include path in output only when we use -nostdinc
since in microsoft toolchain microsoft puts both thing together
add a nostdinc test for that case
---
clang/lib/Driver/ToolChains/MSVC.cpp | 2 ++
clang/test/Driver/aix-toolchain-include.cpp | 11 ++++++++++-
clang/test/Driver/print-cxx-stdlib.cpp | 5 +++++
3 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp
index 45ab10dc12f20..3baa3b366dbe1 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -1452,6 +1452,8 @@ llvm::SmallVector<std::string> MSVCToolChain::getCXXStdlibIncludeDirs(
auto cxxStdlibType = GetCXXStdlibType(DriverArgs);
if (cxxStdlibType == ToolChain::CST_Msvcstl) {
llvm::SmallVector<std::string> vec;
+ if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc))
+ return vec;
std::string includePaths;
auto SysRoot = getDriver().SysRoot;
if (SysRoot.empty()) {
diff --git a/clang/test/Driver/aix-toolchain-include.cpp b/clang/test/Driver/aix-toolchain-include.cpp
index b0074bf0ba1fd..96281e7a81d83 100644
--- a/clang/test/Driver/aix-toolchain-include.cpp
+++ b/clang/test/Driver/aix-toolchain-include.cpp
@@ -196,4 +196,13 @@
// RUN: --sysroot %S/Inputs/aix_ppc_tree \
// RUN: | FileCheck --check-prefix=CHECK-INCLUDE-LIBSTDCXX %s
-// CHECK-INCLUDE-LIBSTDCXX: LLVM ERROR: picking up libstdc++ headers is unimplemented on AIX
+// CHECK-INCLUDE-LIBSTDCXX: LLVM ERROR: picking up non-libc++ headers is unimplemented on AIX
+
+// Check powerpc64-ibm-aix, 64-bit. -stdlib=msvcstl invokes fatal error.
+// RUN: not --crash %clangxx %s 2>&1 -### \
+// RUN: --target=powerpc64-ibm-aix \
+// RUN: -stdlib=libstdc++ \
+// RUN: --sysroot %S/Inputs/aix_ppc_tree \
+// RUN: | FileCheck --check-prefix=CHECK-INCLUDE-MSVCSTL %s
+
+// CHECK-INCLUDE-MSVCSTL: LLVM ERROR: picking up non-libc++ headers is unimplemented on AIX
diff --git a/clang/test/Driver/print-cxx-stdlib.cpp b/clang/test/Driver/print-cxx-stdlib.cpp
index 58620e7ee34dc..0efe034dcfae8 100644
--- a/clang/test/Driver/print-cxx-stdlib.cpp
+++ b/clang/test/Driver/print-cxx-stdlib.cpp
@@ -33,6 +33,11 @@
// RUN: --target=x86_64-pc-windows-msvc \
// RUN: -Xmicrosoft-visualc-tools-root %t/VC/Tools/MSVC/27.1828.18284 \
// RUN: -nostdinc++ \
+// RUN: | FileCheck %s --check-prefix=MSVC-INCLUDES --allow-empty
+// RUN: %clangxx --print-cxx-stdlib-include-dirs \
+// RUN: --target=x86_64-pc-windows-msvc \
+// RUN: -Xmicrosoft-visualc-tools-root %t/VC/Tools/MSVC/27.1828.18284 \
+// RUN: -nostdinc \
// RUN: | FileCheck %s --check-prefix=NO-INCLUDES --allow-empty
// RUN: %clangxx --print-cxx-stdlib-include-dirs -stdlib=libc++ \
// RUN: --target=x86_64-pc-windows-msvc \
More information about the cfe-commits
mailing list