https://github.com/trcrsired created https://github.com/llvm/llvm-project/pull/96417
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 >From 70823f780dc0748446c752f27b52b0f6061bc7e1 Mon Sep 17 00:00:00 2001 From: trcrsired <uwgghhb...@gmail.com> Date: Sun, 23 Jun 2024 00:07:19 -0400 Subject: [PATCH] Support --sysroot= for ${arch}-windows-msvc targets I think it is possible to use the same rule for msvc targets with --target= and --sysroot= See Repository: https://github.com/trcrsired/windows-msvc-sysroot Add sysroot support for msvc MSVC.cpp needs getDriver before using D add stl in parser for -stdlib= Add Vcruntime to runtime list and unwind list MSVC add default runtime lib type and default unwind lib type add a msvc sysroot test use %S instead of /foo --- clang/include/clang/Driver/ToolChain.h | 9 +- clang/lib/Driver/ToolChain.cpp | 9 + clang/lib/Driver/ToolChains/MSVC.cpp | 248 +++++++++++++++++++------ clang/lib/Driver/ToolChains/MSVC.h | 24 ++- clang/test/Driver/msvc-sysroot.cpp | 11 ++ 5 files changed, 232 insertions(+), 69 deletions(-) create mode 100644 clang/test/Driver/msvc-sysroot.cpp 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" _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits