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 `. + +## 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++/` (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 59c93459c64b9..53bdeb642842c 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; 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, @@ -299,6 +293,10 @@ class ToolChain { /// GPUs. virtual std::string getInputFilename(const InputInfo &Input) const; + /// for printing C++ standard library include dirs + virtual llvm::SmallVector + 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 2b79cb9d12c2a..562e60ee81aa3 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -136,23 +136,10 @@ template 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'; } } @@ -2804,6 +2791,8 @@ bool Driver::HandleImmediateArgs(Compilation &C) { case ToolChain::RLT_Libgcc: llvm::outs() << GetFilePath("libgcc.a", TC) << "\n"; break; + default: + break; } return false; } @@ -7027,6 +7016,48 @@ std::string Driver::GetProgramPath(StringRef Name, const ToolChain &TC) const { return std::string(Name); } +static std::optional +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(path); + + return {}; +} + std::string Driver::GetStdModuleManifestPath(const Compilation &C, const ToolChain &TC) const { std::string error = ""; @@ -7034,56 +7065,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 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(path); - - return {}; - }; - - if (std::optional result = evaluate("libc++.so"); result) + if (std::optional 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 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(path); - - return {}; - }; - - if (std::optional result = evaluate("libstdc++.so"); result) + if (std::optional 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 a0124e2cbe781..d848b7c161b8a 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -703,6 +703,29 @@ 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"; +} + +llvm::SmallVector +ToolChain::getCXXStdlibIncludeDirs(const ArgList &Args) const { + ArgStringList CC1Args; + if (Args.hasArg(options::OPT_stdlibxx_isystem)) + AddClangCXXStdlibIsystemArgs(Args, CC1Args); + else + AddClangCXXStdlibIncludeArgs(Args, CC1Args); + + llvm::SmallVector Rets; + for (size_t I = 0; I < CC1Args.size(); ++I) { + StringRef Arg(CC1Args[I]); + if (isIncludeDirArg(Arg) && I + 1 < CC1Args.size()) { + Rets.emplace_back(CC1Args[++I]); + } + } + return Rets; +} + ToolChain::UnwindTableLevel ToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const { return UnwindTableLevel::None; @@ -1578,6 +1601,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 { @@ -1617,6 +1642,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) @@ -1640,6 +1667,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 { @@ -1659,6 +1688,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"); } @@ -1830,6 +1861,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/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp index 586bc08067eff..1e58bf4d3b5cd 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..61cad351e5e60 100644 --- a/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -408,6 +408,9 @@ 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"); + break; } std::string SysRootDir(computeSysRoot()); @@ -454,6 +457,9 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, } break; } + case ToolChain::CST_MSVCSTL: { + break; + } } } switch (GetCXXStdlibType(DriverArgs)) { @@ -465,6 +471,7 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, break; } case ToolChain::CST_Libstdcxx: + case ToolChain::CST_MSVCSTL: break; } } @@ -564,7 +571,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"; @@ -587,6 +594,9 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, TC.getCompilerRTArgString(Args, "crtend", ToolChain::FT_Object); break; } + case (ToolChain::RLT_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..380524b84841e 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 98ace0720343f..698c5ad9d6746 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; } } @@ -3132,6 +3134,8 @@ void AppleMachO::AddCXXStdlibLibArgs(const ArgList &Args, // Otherwise, let the linker search. CmdArgs.push_back("-lstdc++"); break; + case ToolChain::CST_MSVCSTL: + break; } } diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp index abde9fa10482d..04d6cf0df85c0 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..ac2fce11115dc 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/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp index 76c5cafd77bc9..71b94acf1bfb9 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/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 84bc2db6d2913..bddcc1ee48084 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,37 @@ 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; +} + +// 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, @@ -140,50 +172,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 = getTripleWithUnknownVendor(TC); + 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 +625,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 VCToolsDir, VCToolsVersion; if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir)) VCToolsDir = A->getValue(); @@ -819,6 +917,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 +1095,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 +1363,121 @@ 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, getTripleWithUnknownVendor(*this), 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, getTripleWithUnknownVendor(*this), 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, getTripleWithUnknownVendor(*this), 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"); +} + +llvm::SmallVector MSVCToolChain::getCXXStdlibIncludeDirs( + const llvm::opt::ArgList &DriverArgs) const { + auto cxxStdlibType = GetCXXStdlibType(DriverArgs); + if (cxxStdlibType == ToolChain::CST_MSVCSTL) { + llvm::SmallVector vec; + if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc)) + return vec; + std::string includePaths; + auto SysRoot = getDriver().SysRoot; + if (SysRoot.empty()) { + if (!VCToolChainPath.empty()) { + vec.push_back(getSubDirectoryPath(llvm::SubDirectoryType::Include)); + } + } else { + // 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; + } + return ToolChain::getCXXStdlibIncludeDirs(DriverArgs); +} diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h index 8ff8b2815d8df..44dea75e19881 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; @@ -161,8 +160,25 @@ class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain { Tool *getTool(Action::ActionClass AC) const override; Tool *buildLinker() const override; Tool *buildAssembler() const override; + llvm::SmallVector + getCXXStdlibIncludeDirs(const llvm::opt::ArgList &DriverArgs) 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 WinSdkDir, WinSdkVersion, WinSysRoot; std::string VCToolChainPath; llvm::ToolsetLayout VSLayout = llvm::ToolsetLayout::OlderVS; diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index 65120931d8181..26afc211c1cda 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..800634e16490e 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..4a13a36227b75 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..3bd12bc595e29 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); @@ -355,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; diff --git a/clang/test/Driver/aix-ld.c b/clang/test/Driver/aix-ld.c index bedd224eeca9c..f68d821e421b8 100644 --- a/clang/test/Driver/aix-ld.c +++ b/clang/test/Driver/aix-ld.c @@ -656,7 +656,7 @@ // RUN: -stdlib=libstdc++ -nostdinc++ \ // RUN: --sysroot %S/Inputs/aix_ppc_tree \ // RUN: | FileCheck --check-prefix=CHECK-LD-LIBSTDCXX %s -// CHECK-LD-LIBSTDCXX: LLVM ERROR: linking libstdc++ unimplemented on AIX +// CHECK-LD-LIBSTDCXX: LLVM ERROR: linking non-libc++ unimplemented on AIX // Check powerpc-ibm-aix7.1.0.0, 32-bit. -shared. // RUN: %clangxx -x c++ %s 2>&1 -### \ 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/msvc-sysroot.cpp b/clang/test/Driver/msvc-sysroot.cpp new file mode 100644 index 0000000000000..cc50b61665266 --- /dev/null +++ b/clang/test/Driver/msvc-sysroot.cpp @@ -0,0 +1,161 @@ +// 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" + +// --- 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 +#--- 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 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 \