Skip to content

[clang] Support --sysroot= for ${arch}-windows-msvc targets - #96417

Open
trcrsired wants to merge 1 commit into
llvm:mainfrom
trcrsired:msvcsysroot
Open

[clang] Support --sysroot= for ${arch}-windows-msvc targets#96417
trcrsired wants to merge 1 commit into
llvm:mainfrom
trcrsired:msvcsysroot

Conversation

@trcrsired

@trcrsired trcrsired commented Jun 23, 2024

Copy link
Copy Markdown
Contributor

I think it is possible to use the same rule for msvc targets with --target= and --sysroot=

see:
https://github.com/trcrsired/windows-msvc-sysroot
Headers
Windows + CRT Headers Include Directory: include

C++ standard library headers:
(old: With -stdlib=stl, headers should be located in include/c++/stl)
-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

@github-actions

Copy link
Copy Markdown

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be
notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write
permissions for the repository. In which case you can instead tag reviewers by
name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review
by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate
is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' labels Jun 23, 2024
@llvmbot

llvmbot commented Jun 23, 2024

Copy link
Copy Markdown
Member

@llvm/pr-subscribers-backend-systemz
@llvm/pr-subscribers-backend-powerpc
@llvm/pr-subscribers-backend-hexagon
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-driver

Author: cqwrteur (trcrsired)

Changes

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

With -stdlib=libc++, headers should be located in include/c++/v1

Libraries
Libraries should be placed in lib/$TRIPLET

For example. on x86_64-windows-msvc, it should find libs in lib/x86_64-windows-msvc


Full diff: https://github.com/llvm/llvm-project/pull/96417.diff

5 Files Affected:

  • (modified) clang/include/clang/Driver/ToolChain.h (+6-3)
  • (modified) clang/lib/Driver/ToolChain.cpp (+9)
  • (modified) clang/lib/Driver/ToolChains/MSVC.cpp (+187-61)
  • (modified) clang/lib/Driver/ToolChains/MSVC.h (+19-5)
  • (added) clang/test/Driver/msvc-sysroot.cpp (+11)
diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h
index 1f93bd612e9b0..04535a98dd69c 100644
--- a/clang/include/clang/Driver/ToolChain.h
+++ b/clang/include/clang/Driver/ToolChain.h
@@ -95,18 +95,21 @@ class ToolChain {
 
   enum CXXStdlibType {
     CST_Libcxx,
-    CST_Libstdcxx
+    CST_Libstdcxx,
+    CST_Stl,
   };
 
   enum RuntimeLibType {
     RLT_CompilerRT,
-    RLT_Libgcc
+    RLT_Libgcc,
+    RLT_Vcruntime
   };
 
   enum UnwindLibType {
     UNW_None,
     UNW_CompilerRT,
-    UNW_Libgcc
+    UNW_Libgcc,
+    UNW_Vcruntime
   };
 
   enum class UnwindTableLevel {
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 40ab2e91125d1..b3ed8fc6de36d 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -1091,6 +1091,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 {
@@ -1129,6 +1131,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)
@@ -1152,6 +1156,8 @@ ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{
     cxxStdlibType = ToolChain::CST_Libcxx;
   else if (LibName == "libstdc++")
     cxxStdlibType = ToolChain::CST_Libstdcxx;
+  else if (LibName == "stl")
+    cxxStdlibType = ToolChain::CST_Stl;
   else if (LibName == "platform")
     cxxStdlibType = GetDefaultCXXStdlibType();
   else {
@@ -1290,6 +1296,9 @@ void ToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
   case ToolChain::CST_Libstdcxx:
     CmdArgs.push_back("-lstdc++");
     break;
+
+  default:
+    break;
   }
 }
 
diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp
index ca266e3e1d1d3..bf1b6d3b9bc84 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -31,12 +31,12 @@
 #include <cstdio>
 
 #ifdef _WIN32
-  #define WIN32_LEAN_AND_MEAN
-  #define NOGDI
-  #ifndef NOMINMAX
-    #define NOMINMAX
-  #endif
-  #include <windows.h>
+#define WIN32_LEAN_AND_MEAN
+#define NOGDI
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#include <windows.h>
 #endif
 
 using namespace clang::driver;
@@ -95,43 +95,52 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
   // 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.getLastArg(options::OPT__SLASH_vctoolsdir,
-                      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.getLastArg(options::OPT__SLASH_winsdkdir,
-                      options::OPT__SLASH_winsysroot)) {
-    if (TC.useUniversalCRT()) {
-      std::string UniversalCRTLibPath;
-      if (TC.getUniversalCRTLibraryPath(Args, UniversalCRTLibPath))
+  auto SysRoot = TC.getDriver().SysRoot;
+  if (SysRoot.empty()) {
+    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.getLastArg(options::OPT__SLASH_vctoolsdir,
+                        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.getLastArg(options::OPT__SLASH_winsdkdir,
+                        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));
+  } else {
+    const std::string MultiarchTriple =
+        TC.getMultiarchTriple(TC.getDriver(), TC.getTriple(), SysRoot);
+    std::string SysRootLib = "-libpath:" + SysRoot + "/lib";
+    CmdArgs.push_back(Args.MakeArgString(SysRootLib + '/' + MultiarchTriple));
+    CmdArgs.push_back(Args.MakeArgString(SysRootLib));
   }
 
   if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L))
@@ -207,13 +216,14 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
         CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
       // Make sure the dynamic runtime thunk is not optimized out at link time
       // to ensure proper SEH handling.
-      CmdArgs.push_back(Args.MakeArgString(
-          TC.getArch() == llvm::Triple::x86
-              ? "-include:___asan_seh_interceptor"
-              : "-include:__asan_seh_interceptor"));
+      CmdArgs.push_back(
+          Args.MakeArgString(TC.getArch() == llvm::Triple::x86
+                                 ? "-include:___asan_seh_interceptor"
+                                 : "-include:__asan_seh_interceptor"));
       // Make sure the linker consider all object files from the dynamic runtime
       // thunk.
-      CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") +
+      CmdArgs.push_back(Args.MakeArgString(
+          std::string("-wholearchive:") +
           TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk")));
     } else if (DLL) {
       CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk"));
@@ -224,7 +234,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
         // This is necessary because instrumented dlls need access to all the
         // interface exported by the static lib in the main executable.
         CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") +
-            TC.getCompilerRT(Args, Lib)));
+                                             TC.getCompilerRT(Args, Lib)));
       }
     }
   }
@@ -430,6 +440,11 @@ MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
       RocmInstallation(D, Triple, Args) {
   getProgramPaths().push_back(getDriver().Dir);
 
+  auto SysRoot = getDriver().SysRoot;
+  if (!SysRoot.empty()) {
+    return;
+  }
+
   std::optional<llvm::StringRef> VCToolsDir, VCToolsVersion;
   if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir))
     VCToolsDir = A->getValue();
@@ -602,8 +617,8 @@ static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) {
   if (!llvm::ConvertUTF8toWide(ClExe.c_str(), ClExeWide))
     return Version;
 
-  const DWORD VersionSize = ::GetFileVersionInfoSizeW(ClExeWide.c_str(),
-                                                      nullptr);
+  const DWORD VersionSize =
+      ::GetFileVersionInfoSizeW(ClExeWide.c_str(), nullptr);
   if (VersionSize == 0)
     return Version;
 
@@ -620,7 +635,7 @@ static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) {
     return Version;
 
   const unsigned Major = (FileInfo->dwFileVersionMS >> 16) & 0xFFFF;
-  const unsigned Minor = (FileInfo->dwFileVersionMS      ) & 0xFFFF;
+  const unsigned Minor = (FileInfo->dwFileVersionMS) & 0xFFFF;
   const unsigned Micro = (FileInfo->dwFileVersionLS >> 16) & 0xFFFF;
 
   Version = VersionTuple(Major, Minor, Micro);
@@ -647,6 +662,17 @@ 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);
+    addSystemInclude(DriverArgs, CC1Args,
+                     SysRoot + "/include/" + MultiarchTriple);
+    addSystemInclude(DriverArgs, CC1Args, SysRoot + "/include");
+    return;
+  }
+
   // Add %INCLUDE%-like directories from the -imsvc flag.
   for (const auto &Path : DriverArgs.getAllArgValues(options::OPT__SLASH_imsvc))
     addSystemInclude(DriverArgs, CC1Args, Path);
@@ -763,12 +789,11 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
   // As a fallback, select default install paths.
   // FIXME: Don't guess drives and paths like this on Windows.
   const StringRef Paths[] = {
-    "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
-    "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
-    "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
-    "C:/Program Files/Microsoft Visual Studio 8/VC/include",
-    "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
-  };
+      "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
+      "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
+      "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
+      "C:/Program Files/Microsoft Visual Studio 8/VC/include",
+      "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"};
   addSystemIncludes(DriverArgs, CC1Args, Paths);
 #endif
 }
@@ -776,6 +801,24 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
 void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
                                                  ArgStringList &CC1Args) const {
   // FIXME: There should probably be logic here to find libc++ on Windows.
+  if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
+                        options::OPT_nostdincxx))
+    return;
+  if (getDriver().SysRoot.empty())
+    return;
+  switch (GetCXXStdlibType(DriverArgs)) {
+  case ToolChain::CST_Stl:
+    addStlIncludePaths(DriverArgs, CC1Args);
+    break;
+  case ToolChain::CST_Libstdcxx:
+    addLibStdCXXIncludePaths(DriverArgs, CC1Args);
+    break;
+  case ToolChain::CST_Libcxx:
+    addLibCxxIncludePaths(DriverArgs, CC1Args);
+    break;
+  default:
+    break;
+  }
 }
 
 VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D,
@@ -877,7 +920,8 @@ static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL,
           DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline));
           break;
         case '1':
-          DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions));
+          DAL.AddFlagArg(A,
+                         Opts.getOption(options::OPT_finline_hint_functions));
           break;
         case '2':
         case '3':
@@ -912,11 +956,10 @@ static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL,
       }
       if (SupportsForcingFramePointer) {
         if (OmitFramePointer)
-          DAL.AddFlagArg(A,
-                         Opts.getOption(options::OPT_fomit_frame_pointer));
+          DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer));
         else
-          DAL.AddFlagArg(
-              A, Opts.getOption(options::OPT_fno_omit_frame_pointer));
+          DAL.AddFlagArg(A,
+                         Opts.getOption(options::OPT_fno_omit_frame_pointer));
       } else {
         // Don't warn about /Oy- in x86-64 builds (where
         // SupportsForcingFramePointer is false).  The flag having no effect
@@ -1027,3 +1070,86 @@ void MSVCToolChain::addClangTargetOptions(
   if (Arg *A = DriverArgs.getLastArgNoClaim(options::OPT_marm64x))
     A->ignoreTargetSpecific();
 }
+
+void MSVCToolChain::addStlIncludePaths(
+    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++/stl";
+  addSystemInclude(DriverArgs, CC1Args, TargetDir);
+
+  // Second add the generic one.
+  addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/stl");
+}
+
+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 3950a8ed38e8b..609ce1c738751 100644
--- a/clang/lib/Driver/ToolChains/MSVC.h
+++ b/clang/lib/Driver/ToolChains/MSVC.h
@@ -71,9 +71,7 @@ class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain {
     return llvm::DebuggerKind::Default;
   }
 
-  unsigned GetDefaultDwarfVersion() const override {
-    return 4;
-  }
+  unsigned GetDefaultDwarfVersion() const override { return 4; }
 
   std::string getSubDirectoryPath(llvm::SubDirectoryType Type,
                                   llvm::StringRef SubdirParent = "") const;
@@ -100,8 +98,8 @@ class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain {
   void AddHIPRuntimeLibArgs(const llvm::opt::ArgList &Args,
                             llvm::opt::ArgStringList &CmdArgs) const override;
 
-  bool getWindowsSDKLibraryPath(
-      const llvm::opt::ArgList &Args, std::string &path) const;
+  bool getWindowsSDKLibraryPath(const llvm::opt::ArgList &Args,
+                                std::string &path) const;
   bool getUniversalCRTLibraryPath(const llvm::opt::ArgList &Args,
                                   std::string &path) const;
   bool useUniversalCRT() const;
@@ -132,7 +130,23 @@ class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain {
 
   Tool *buildLinker() const override;
   Tool *buildAssembler() const override;
+
 private:
+  CXXStdlibType GetDefaultCXXStdlibType() const override {
+    return ToolChain::CST_Stl;
+  }
+  RuntimeLibType GetDefaultRuntimeLibType() const override {
+    return ToolChain::RLT_Vcruntime;
+  }
+  UnwindLibType GetDefaultUnwindLibType() const override {
+    return ToolChain::UNW_Vcruntime;
+  }
+  void addStlIncludePaths(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..9e58729ec57e9
--- /dev/null
+++ b/clang/test/Driver/msvc-sysroot.cpp
@@ -0,0 +1,11 @@
+// RUN: %clangxx --target=x86_64-unknown-windows-msvc -### --sysroot=%S -fuse-ld=lld %s 2>&1 | FileCheck --check-prefix=COMPILE %s
+// COMPILE: clang{{.*}}" "-cc1"
+// COMPILE: "-isysroot" "[[SYSROOT:[^"]+]]"
+// COMPILE: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/x86_64-unknown-windows-msvc/c++/stl"
+// COMPILE: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/c++/stl"
+
+// RUN: %clangxx --target=aarch64-unknown-windows-msvc -### --sysroot=%S -fuse-ld=lld %s 2>&1 | FileCheck --check-prefix=COMPILE %s
+// COMPILE: clang{{.*}}" "-cc1"
+// COMPILE: "-isysroot" "[[SYSROOT:[^"]+]]"
+// COMPILE: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/aarch64-unknown-windows-msvc/c++/stl"
+// COMPILE: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/c++/stl"

@trcrsired trcrsired changed the title Support --sysroot= for ${arch}-windows-msvc targets [clang] Support --sysroot= for ${arch}-windows-msvc targets Jun 26, 2024
@Sirraide
Sirraide requested review from AaronBallman and MaskRay June 26, 2024 04:55
@trcrsired

Copy link
Copy Markdown
Contributor Author

@MaskRay

@zmodem zmodem left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've read half the patch so far, but wanted to ask before continuing: would it be possible (and simpler) to extend the /winsysroot support somehow to also handle --sysroot?

(It would also be easier to review if the unrelated formatting changes were removed or split to a separate PR.)

Comment thread clang/include/clang/Driver/ToolChain.h Outdated
Comment thread clang/lib/Driver/ToolChain.cpp Outdated
Comment thread clang/lib/Driver/ToolChains/MSVC.cpp
Comment thread clang/lib/Driver/ToolChains/MSVC.cpp Outdated
@trcrsired

trcrsired commented Jul 1, 2024

Copy link
Copy Markdown
Contributor Author

I've read half the patch so far, but wanted to ask before continuing: would it be possible (and simpler) to extend the /winsysroot support somehow to also handle --sysroot?

(It would also be easier to review if the unrelated formatting changes were removed or split to a separate PR.)

no. i do not use clang-cl. /winsysroot is not sysroot. /winsysroot is for clang-cl. not clang itself

sysroot is what the usually the clang and GCC means. That is not a semantics for msvc.

I have checked the code first clang does not support /winsysroot, second they have very different meanings which make them incompatible. Just use --sysroot because --sysroot matches the behavior of other platforms, including GNU variants of windows targets like x86_64-windows-gnu.

BTW using --sysroot gives the same semantics for build systems like build tools cmake or xmake.

@trcrsired

Copy link
Copy Markdown
Contributor Author

I've read half the patch so far, but wanted to ask before continuing: would it be possible (and simpler) to extend the /winsysroot support somehow to also handle --sysroot?

(It would also be easier to review if the unrelated formatting changes were removed or split to a separate PR.)

I have avoided formatting as much as possible. However, the llvm CI does not pass if I do not format it.

@zmodem

zmodem commented Jul 1, 2024

Copy link
Copy Markdown
Contributor

I've read half the patch so far, but wanted to ask before continuing: would it be possible (and simpler) to extend the /winsysroot support somehow to also handle --sysroot?
(It would also be easier to review if the unrelated formatting changes were removed or split to a separate PR.)

no. i do not use clang-cl. /winsysroot is not sysroot. /winsysroot is for clang-cl. not clang itself

sysroot is what the usually the clang and GCC means. That is not a semantics for msvc.

I have checked the code first clang does not support /winsysroot, second they have very different meanings which make them incompatible. Just use --sysroot because --sysroot matches the behavior of other platforms, including GNU variants of windows targets like x86_64-windows-gnu.

BTW using --sysroot gives the same semantics for build systems like build tools cmake or xmake.

I didn't mean that you should use /winsysroot, I was asking whether --sysroot and /winsysroot could share code for implementation.

@trcrsired

trcrsired commented Jul 1, 2024

Copy link
Copy Markdown
Contributor Author

I've read half the patch so far, but wanted to ask before continuing: would it be possible (and simpler) to extend the /winsysroot support somehow to also handle --sysroot?
(It would also be easier to review if the unrelated formatting changes were removed or split to a separate PR.)

no. i do not use clang-cl. /winsysroot is not sysroot. /winsysroot is for clang-cl. not clang itself
sysroot is what the usually the clang and GCC means. That is not a semantics for msvc.
I have checked the code first clang does not support /winsysroot, second they have very different meanings which make them incompatible. Just use --sysroot because --sysroot matches the behavior of other platforms, including GNU variants of windows targets like x86_64-windows-gnu.
BTW using --sysroot gives the same semantics for build systems like build tools cmake or xmake.

I didn't mean that you should use /winsysroot, I was asking whether --sysroot and /winsysroot could share code for implementation.

They couldn't. They mean different things.

  1. Settings --sysroot will disable all existing environment settings. The behavior is different.
  2. The file structures are completely different. winsysroot has a very complicated file structures that need to reference while --sysroot is not. /winsysroot reuses microsoft's file structures while --sysroot is GNU and LLVM's file structures.
  3. --sysroot supports -stdlib=libc++ while other settings do not.

const std::string MultiarchTriple =

Other toggles only work when --sysroot is null. This is a completely different setting than winsysroot and many other settings such as environmental variables. winsysroot still references environmental variable, which are completely different behavior. I suggest deprecating winsysroot completely.

@trcrsired

Copy link
Copy Markdown
Contributor Author

@zmodem Looks like clang-formatting makes you harder to review the code, I will try to use the upstream code and avoiding formatting.

@trcrsired
trcrsired force-pushed the msvcsysroot branch 7 times, most recently from d716838 to e3f96da Compare July 1, 2024 21:25
@trcrsired

trcrsired commented Jul 1, 2024

Copy link
Copy Markdown
Contributor Author

@zmodem Can you review it again? I have removed the formatting part here. Although I disagree with -stdlib=msstl thing. Can you check any other part that is problematic first? Ty

@trcrsired

Copy link
Copy Markdown
Contributor Author

Remove mentioning of repo url in commit

@zmodem

zmodem commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

I've always kind of held out this idea that clang[++] are perfectly reasonable frontends to use when targeting an MSVC-environment with an official Microsoft Windows SDK

Me too, but isn't this PR a different idea? This is about using clang with MSVC/Win SDK turned into a Unix-style sysroot, which seems like a much narrower use case.

I think it would be better if the driver could work with the MSVC/SDK as-is, rather than forcing the user to change the SDK into a form that the driver likes (even if it's a "standard" form in the sense that other sysroots use it). That would probably require more work, such as supporting case-insensitive includes, but seems like it would be much user friendlier.

But I won't block this if there's otherwise strong support for it.

@trcrsired

Copy link
Copy Markdown
Contributor Author

I've always kind of held out this idea that clang[++] are perfectly reasonable frontends to use when targeting an MSVC-environment with an official Microsoft Windows SDK

Me too, but isn't this PR a different idea? This is about using clang with MSVC/Win SDK turned into a Unix-style sysroot, which seems like a much narrower use case.

I think it would be better if the driver could work with the MSVC/SDK as-is, rather than forcing the user to change the SDK into a form that the driver likes (even if it's a "standard" form in the sense that other sysroots use it). That would probably require more work, such as supporting case-insensitive includes, but seems like it would be much user friendlier.

But I won't block this if there's otherwise strong support for it.

cross compiling is not a narrow use bro.

And this PR will allow using libc++ with microsoft sdk too and unfortunately microsoft puts C headers and MSVC STL headers together. Without a UNIX style sysroot that seperates msvc stl headers into a seperate include/c++/msvcstl there is no way to get it work.

@trcrsired

trcrsired commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

I've always kind of held out this idea that clang[++] are perfectly reasonable frontends to use when targeting an MSVC-environment with an official Microsoft Windows SDK

Me too, but isn't this PR a different idea? This is about using clang with MSVC/Win SDK turned into a Unix-style sysroot, which seems like a much narrower use case.
I think it would be better if the driver could work with the MSVC/SDK as-is, rather than forcing the user to change the SDK into a form that the driver likes (even if it's a "standard" form in the sense that other sysroots use it). That would probably require more work, such as supporting case-insensitive includes, but seems like it would be much user friendlier.
But I won't block this if there's otherwise strong support for it.

cross compiling is not a narrow use bro.

And this PR will allow using libc++ with microsoft sdk too and unfortunately microsoft puts C headers and MSVC STL headers together. Without a UNIX style sysroot that seperates msvc stl headers into a seperate include/c++/msvcstl there is no way to get it work.

in fact i use clang on my android phone to cross compile windows on arm .exe binaries and run eith wine every day. It is literally native compilation for me at this point.

I think the reason you said cross compiling to windows is narrow probably because you come from the background of big tech such as google which relies on libc++ on windows that is fine. But for small devs like me who need toolchains to run on android cross compilung is a huge big deal.
Screenshot_20260821-182549

@Andarwinux

Copy link
Copy Markdown
Member

FYI, MinGW can’t keep up with Windows SDK. The reason people still rely on MinGW today is largely because Windows SDK’s directory structure is very complicated for cross-compilation. This PR makes it possible for users who want to move away from MinGW to switch to Windows SDK - there’s huge potential demand in this PR.

@trcrsired

Copy link
Copy Markdown
Contributor Author

FYI, MinGW can’t keep up with Windows SDK. The reason people still rely on MinGW today is largely because Windows SDK’s directory structure is very complicated for cross-compilation. This PR makes it possible for users who want to move away from MinGW to switch to Windows SDK - there’s huge potential demand in this PR.

thank you!

@trcrsired

trcrsired commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author
image

Here is a typical installation of microsoft visual C++ toolchain. You can see microsoft puts standard C header files with C++ headers together which blocks the possibility of using libc++ or even GCC libstdc++ with microsoft's toolchain together unless you are doing a unix style sysroot.

While if you look at a UNIX Style Sysroot,

image

C++ headers would be a seperate directory for compiler to seek so we can replace C++ standard libraries or C++ standard library. On MSVC toolchain file directory it is all impossible. In fact microsoft does not even want you to put 3rd party headers in the directory since they do not want us to use command lines but the visual studio which is where their money comes from.

With this patch at least you can use a sysroot that only contains libc++ to work with microsoft toolchain although i guess we will still see file conflicts. While you can always use a full scale UNIX style sysroot to work

BTW, mingw-w64 (windows-gnu) target is still very useful for people like me to do canadian compilation to build compilers from Linux to Windows while keeps everything open sourced and compiled.

@trcrsired

trcrsired commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

FYI, MinGW can’t keep up with Windows SDK. The reason people still rely on MinGW today is largely because Windows SDK’s directory structure is very complicated for cross-compilation. This PR makes it possible for users who want to move away from MinGW to switch to Windows SDK - there’s huge potential demand in this PR.

Also WOA's official aarch64-w64-mingw32-g++ is still unavailable although i have made it works. Microsoft devs pushed wrong patches to upstream.

https://github.com/trcrsired/gcc-releases/releases

@mstorsjo

Copy link
Copy Markdown
Member

I've always kind of held out this idea that clang[++] are perfectly reasonable frontends to use when targeting an MSVC-environment with an official Microsoft Windows SDK

Me too, but isn't this PR a different idea? This is about using clang with MSVC/Win SDK turned into a Unix-style sysroot, which seems like a much narrower use case.

Yes, exactly. The discussion here conflates a lot of different concepts.

It's perfectly possible to use clang/clang++ to compile with a Microsoft SDK already, on Windows and cross compiling. The normal method of accessing the SDK (through the INCLUDE and LIB env variables for specifying locations) works just like it does for clang-cl - the flavour of driver doesn't make any difference there.

If you want to manually specify an SDK location instead of passing it through the environment, then you can use the /winsysroot option with clang-cl. It seems that Clang supports the same option named -Xmicrosoft-windows-sys-root with the GNU style clang/clang++ drivers as well.

This new option isn't about clang-cl vs clang/clang++ driver style, but just about supporting a different kind of SDK layout. If considered useful, the same SDK layout should of course also be usable with clang-cl as well. So please isolate the discussion around the SDK layout and skip the other unrelated parts.

I think it would be better if the driver could work with the MSVC/SDK as-is, rather than forcing the user to change the SDK into a form that the driver likes (even if it's a "standard" form in the sense that other sysroots use it).

This already works, as far as I know - through the /winsysroot and -Xmicrosoft-windows-sys-root options.

That would probably require more work, such as supporting case-insensitive includes, but seems like it would be much user friendlier.

Supporting case insensitive includes would indeed be nice.

Please just merge it since this PR has been over 2 years.

Just because the PR has been up for a long time isn't a reason for cutting the discussion short - especially for something that defines new public interfaces in how Clang interacts with other toolchain components.

@trcrsired

Copy link
Copy Markdown
Contributor Author

This already works, as far as I know - through the /winsysroot and -Xmicrosoft-windows-sys-root options.

/winsysroot was defined poorly to begin with although it is another story.

That would probably require more work, such as supporting case-insensitive includes, but seems like it would be much user friendlier.

Supporting case insensitive includes would indeed be nice.

I strongly oppose case insensitive includes. Linux kernel headers DO use the same insensitive include file names with case sensitive headers. It breaks code. You might say it can be just an option, but an option provide fragmentations and it will create more problems for testing, considering C++ headers situation are already bad enough.

include/linux/netfilter
image
xt_connmark.h vs xt_CONNMARK.h

xt_tcpmss.h vs xt_TCPMSS.h

@sharadhr

Copy link
Copy Markdown
Contributor

I think the spirit of this MR is useful, allowing clang --sysroot on any platform to target {arch}-pc-windows-msvc.

However, I agree with @zmodem when he says this:

This is about using clang with MSVC/Win SDK turned into a Unix-style sysroot

@trcrsired, I don't think it was said that 'cross-compilation is a narrow scenario', instead it was 'making the Windows SDK and MSVC STL into a Unix-like sysroot' is a narrow scenario, which is broadly true.

Shoehorning the Windows SDK and MSVC STL into a Unix-like layout is, in my opinion, too much to ask of the user. We can support this scenario, I won't say no either, but I believe the proper way is to get Clang to accept the layout as-is from the Build Tools installer (for example). Surely clang-cl already has all this machinery, and it is a matter of wiring up the discovered paths to clang++, with case-insensitive handling on case-sensitive filesystems.

The most obvious, first-party way to set up an MSVC ABI + MSVC STL cross-compile environment on Unix-like environments would be to use the above installer on Windows itself or maybe WINE and install it to a case-insensitive FS, mount that filesystem on the Unix-like host, and then write clang --sysroot=.... If you are running clang on your Android phone, this would entail copy-pasting the Windows SDK and MSVC STL into an SD card, loading it up, and then writing clang --sysroot=/sdcard/VC/... or something similar.

I'm not sure this functionality is present in the current PR, which is what I discussed in the first place. There is a lot of demand for this setup, I agree, but asking the user to do this extra work is not very ergonomic (and now that the links to the external GitHub page and scripts are gone, is less discoverable as well).

@trcrsired

trcrsired commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

@trcrsired, I don't think it was said that 'cross-compilation is a narrow scenario', instead it was 'making the Windows SDK and MSVC STL into a Unix-like sysroot' is a narrow scenario, which is broadly true.

case insensitivity (similar things such as EBCDIC, wchar_t, Big endian) was a historical mistake to begin with. Let's do not make things worse by creating more fragmentations. I have said there are libraries out there (even the linux kernel header files) have case sensitive headers. You cannot really implement this without breaking code.

Also the argument of packaing as UNIX style is too much ask would be true for basically any targets over there. You always need to build libc and install it to create a UNIX style sysroot. In fact even llvm itself uses UNIX style sysroot packaging on windows.
Anyone who knows how to do cross compiling knows how UNIX style works. It is literally the defact standard out there and other languages expect that too.

mingw-w64 does exact the same thing. UNIX style sysroot + case insensitivity. All i did is to match the behavior of mingw-w64 which is exactly what we should be doing.

@sharadhr

Copy link
Copy Markdown
Contributor

Let's do not make things worse by creating more fragmentations

But this PR does precisely that, by expecting a non-standard directory layout for --sysroot. By non-standard I mean modified from what the vendor provides. It might be a 'de-facto standard for UNIX' but it is not the standard for Windows.

If the goal is to get --sysroot to expect {arch}-pc-windows-msvc then I believe the correct solution is to alias it to -Xmicrosoft-windows-sys-root when the argument value is {arch}-pc-windows-msvc, and ensure case-insensitivity is correctly handled in the driver. As it is, this PR is therefore incomplete.

@trcrsired

trcrsired commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Let's do not make things worse by creating more fragmentations

But this PR does precisely that, by expecting a non-standard directory layout for --sysroot. By non-standard I mean modified from what the vendor provides. It might be a 'de-facto standard for UNIX' but it is not the standard for Windows.

If the goal is to get --sysroot to expect {arch}-pc-windows-msvc then I believe the correct solution is to alias it to -Xmicrosoft-windows-sys-root when the argument value is {arch}-pc-windows-msvc, and ensure case-insensitivity is correctly handled in the driver. As it is, this PR is therefore incomplete.

  1. POSIX is the OS standard.
  2. MinGW does this. CYGWIN does this. MSYS2 does this. Every windows platform besides this does it.
  3. Case insensitivity is a filesystem thing. In fact ntfs and refs allows case sensitive too. You are really just breaking code by doing so.

Standard clearly means POSIX standard under this context. Even microsoft has to follow POSIX (we had POSIX subsystem back then in windows). and Windows CRT followed POSIX designs too. It is the standard

@trcrsired

Copy link
Copy Markdown
Contributor Author

Even Linus Torvalds agrees with that.
https://www.phoronix.com/news/Linus-Torvalds-Anti-Case-Fold
https://lore.kernel.org/lkml/CAHk-=wjajMJyoTv2KZdpVRoPn0LFZ94Loci37WLVXmMxDbLOjg@mail.gmail.com/

Please no more case insensitive mess thanks.

Case-insensitive names are horribly wrong, and you shouldn't have done
them at all. The problem wasn't the lack of testing, the problem was
implementing it in the first place.

The problem is then compounded by "trying to do it right", and in the
process doing it horrible wrong indeed, because "right" doesn't exist,
but trying to will make random bytes have very magical meaning.
Dammit. Case sensitivity is a BUG. The fact that filesystem people
*still* think it's a feature, I cannot understand. It's like they
revere the old FAT filesystem _so_ much that they have to recreate it
- badly.

@trcrsired

trcrsired commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Let's do not make things worse by creating more fragmentations

But this PR does precisely that, by expecting a non-standard directory layout for --sysroot. By non-standard I mean modified from what the vendor provides. It might be a 'de-facto standard for UNIX' but it is not the standard for Windows.

If the goal is to get --sysroot to expect {arch}-pc-windows-msvc then I believe the correct solution is to alias it to -Xmicrosoft-windows-sys-root when the argument value is {arch}-pc-windows-msvc, and ensure case-insensitivity is correctly handled in the driver. As it is, this PR is therefore incomplete.

POSIX is the OS standard for all OSes (including linux, windows, mac, bsd, whatever you call it) not just "for UNIX". Linux is not even UNIX. It is a common misunderstanding. Windows existence does not justifiy POSIX not being the standard for OS. Just like Americans use miles instead of kms do not mean SI is not the standard for all units. Even ISO C++ has to reserve posix namespace because it is the OS standard.

@sharadhr

sharadhr commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

I don't think POSIX or Torvalds' opinions on case insensitivity really matters here. The fact is that the Windows SDK and MSVC STL are written, delivered and expected to be used in a case-insensitive environment. We have a few choices:

  1. Accept it as-is, and handle case-insensitivity in the driver, which is clang-cl's behaviour, which is least-surprise for the end-user
  2. 'rewrite the world', which is what MinGW, Cygwin, et al have done, but require dragging along an entirely separate sysroot, which may diverge from the vendor in features, correctness, and behaviour, meaning libraries like https://github.com/microsoft/wil do not compile with a MinGW toolchain
  3. Manually mangle the vendor-provided sysroot, attempted in this PR, or in projects like https://github.com/Jake-Shadle/xwin. This is error-prone.

@trcrsired

Copy link
Copy Markdown
Contributor Author

Linus Torvalds @torvalds:

match some security-sensitive pattern". And then the shit-for-brains
filesystem ends up matching that pattern *anyway*, because the people
who do case insensitivity *INVARIABLY* do things like ignore
non-printing characters, so now "case insensitive" also means
"insensitive to other things too".

For examples of this, see commits

  5c26d2f1d3f5 ("unicode: Don't special case ignorable code points")

and

  231825b2e1ff ("Revert "unicode: Don't special case ignorable code points"")

and cry.

Hint: ❤ and ❤️ are two unicode characters that differ only in
ignorable code points. And guess what? The cray-cray incompetent
people who want those two to compare the same will then also have
other random - and perhaps security-sensitive - files compare the
same, just because they have ignorable code points in them.

So now every single user mode program that checks that they don't
touch special paths is basically open to being fooled into doing
things they explicitly checked they shouldn't be doing. And no, that
isn't something unusual or odd. *Lots* of programs do exactly that.```

He even argued case sensitivity is a security flaw.

@trcrsired

trcrsired commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

I don't think POSIX or Torvalds' opinions on case insensitivity really matters here. The fact is that the Windows SDK and MSVC STL are written, delivered and expected to be used in a case-insensitive environment. We have a few choices:

  1. Accept it as-is, and handle case-insensitivity in the driver, which is clang-cl's behaviour, which is least-surprise for the end-user
  2. 'rewrite the world', which is what MinGW, Cygwin, et al have done, but require dragging along an entirely separate sysroot, which may diverge from the vendor in features, correctness, and behaviour
  3. Manually mangle the vendor-provided sysroot, attempted in this PR, or in projects like https://github.com/Jake-Shadle/xwin. This is error-prone.

MinGW is just windows using a different C++ runtime. Cygwin is not, cygwin is more like reimplementing entire user space of windows.
it really matters. Because Linux kernel DO have case sensitivity headers so with many other projects. case insensitivity breaks code because of that.

When i use --sysroot to a UNIX style sysroot that does not find my headers, that was the real surprise to me.

https://github.com/rust-cross/cargo-xwin

Jake-Shadle/xwin#138
In fact solutions like this cannot even build go language's standard library. The reason i create windows-msvc-sysroot is exactly because it does not work. You are proving my argument that it does not work.

@trcrsired

trcrsired commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Jake-Shadle/xwin#138

https://github.com/rust-cross/cargo-xwin

Oh i remembered wrong. it was cargo-xwin that uses my windows-msvc-sysroot.

@trcrsired

trcrsired commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author
image

See case insensitive "same" file names with different cases?

@trcrsired

trcrsired commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

It's perfectly possible to use clang/clang++ to compile with a Microsoft SDK already, on Windows and cross compiling. The normal method of accessing the SDK (through the INCLUDE and LIB env variables for specifying locations) works just like it does for clang-cl - the flavour of driver doesn't make any difference there.

Environmental variables to change how the functionalities are also very bad idea. There are so many things that can affect it in a very surprise way. It will also force scripts to guard them (just like a lot of scripts have to use LC_ALL="C.UTF-8" all the time). it is really bad.

I really do not see what is the real opposition here giving the fact --sysroot works for both POSIX style standard sysroot and /winsysroot now and it provides libc++ support. Trying to work things around like introducing case insensitive to LLVM is a security hazard and purely just wrong (Linus Torvalds was proven right on this) and they break code (because i have shown you there are different filenames with the same case sensitive filenames in Linux kernels header files).

For projects like you said "wil" that has to with their cmake scripts. CMake installs things on POSIX style too (so with llvm) on windows. I do not see what is real argument rather than poorly implemented /winsysroot to begin with.

@trcrsired

trcrsired commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author
image Even LLVM itself does POSIX style sysroot on windows for itself what a joke. The "wil" argument is completely flawed given cmake does exactly what POSIX style sysroot does.

@trcrsired trcrsired closed this Aug 21, 2026
@trcrsired trcrsired reopened this Aug 21, 2026
@trcrsired

Copy link
Copy Markdown
Contributor Author

@trcrsired, I don't think it was said that 'cross-compilation is a narrow scenario', instead it was 'making the Windows SDK and MSVC STL into a Unix-like sysroot' is a narrow scenario, which is broadly true.

It is not true. Or LLVM itself won't package this way on windows. Blocking PR like this proves my point you said "cross compilation is a narrow scenario" since literally this is the only sound solution i have tested.

@trcrsired

Copy link
Copy Markdown
Contributor Author

@trcrsired

Copy link
Copy Markdown
Contributor Author
  1. 'rewrite the world', which is what MinGW, Cygwin, et al have done, but require dragging along an entirely separate sysroot, which may diverge from the vendor in features, correctness, and behaviour, meaning libraries like https://github.com/microsoft/wil do not compile with a MinGW toolchain

But it will get easily compiled with windows-msvc-sysroot which is exactly the point here.
https://github.com/trcrsired/windows-msvc-sysroot

@trcrsired

trcrsired commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

The most obvious, first-party way to set up an MSVC ABI + MSVC STL cross-compile environment on Unix-like environments would be to use the above installer on Windows itself or maybe WINE and install it to a case-insensitive FS, mount that filesystem on the Unix-like host, and then write clang --sysroot=.... If you are running clang on your Android phone, this would entail copy-pasting the Windows SDK and MSVC STL into an SD card, loading it up, and then writing clang --sysroot=/sdcard/VC/... or something similar.

What world are you living in? There is no sdcard slot on phones any more. In fact Apple is trying to create portless iphone with no ports at all. Users have been gradually losing their rights to their own property. You will own nothing and you will be happy, World economic forum 2030

Also clang/clang++ are not MSVC style (or you won't have clang-cl that accepts MSVC flags). They are GNU style frontend even for target like windows-msvc. It should follow GNU and POSIX style rules not MSVC ones.

@trcrsired

trcrsired commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Just because the PR has been up for a long time isn't a reason for cutting the discussion short - especially for something that defines new public interfaces in how Clang interacts with other toolchain components.

Feel free to have more discussions. But something like how talking about POSIX style sysroot being not the de facto standard and even llvm itself is packaged this way really leads the discussions to nowhere. It is not constructive, it does not contribute to help on i should do. I am the one who does the real hard work and it is a painfull infinite grind for me giving the fact i do not even have a job to feed myself.

Case insensitive is something i strongly oppose mainly for it is known to be implemented very buggy and often security flaws. And there are real world code out there (like linux kernel headers i shown here) use header file names differ only by case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend:Hexagon backend:PowerPC backend:SystemZ clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.