From af5f468228472ef2d4f58c2ac51842d4a6d91c9d Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 7 Mar 2023 10:10:31 -0800 Subject: [PATCH] MSVC: support version preference with search Extend the logic for the WinSDK and UCRT handling to prefer a user specified version of the VisualC++ tools and Windows SDK. This allows us to now perform the regular search for the installation but select the exact version of the SDK or VC++ tools to override the latest version. Similar to the other flags controlling this behaviour, if the user specifies a value, we will not perform validation on the input and will attempt to prefer that, particularly in the case of VisualC++ tools where no fallback occurs. Reviewed by: hans Differential Revision: https://reviews.llvm.org/D145517 --- clang/lib/Driver/ToolChains/MSVC.cpp | 19 +++++++++++-- lld/COFF/Driver.cpp | 2 +- llvm/include/llvm/WindowsDriver/MSVCPaths.h | 10 +++++-- .../Orc/COFFVCRuntimeSupport.cpp | 2 +- llvm/lib/WindowsDriver/MSVCPaths.cpp | 28 ++++++++++++------- 5 files changed, 44 insertions(+), 17 deletions(-) diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 6f7db528e23a..b23d0aa2f1b8 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -440,8 +440,8 @@ MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple, WinSysRoot, VCToolChainPath, VSLayout) || llvm::findVCToolChainViaEnvironment(getVFS(), VCToolChainPath, VSLayout) || - llvm::findVCToolChainViaSetupConfig(getVFS(), VCToolChainPath, - VSLayout) || + llvm::findVCToolChainViaSetupConfig(getVFS(), VCToolsVersion, + VCToolChainPath, VSLayout) || llvm::findVCToolChainViaRegistry(VCToolChainPath, VSLayout); } @@ -546,6 +546,10 @@ bool MSVCToolChain::getWindowsSDKLibraryPath(const ArgList &Args, llvm::SmallString<128> libPath(sdkPath); llvm::sys::path::append(libPath, "Lib"); + if (sdkMajor >= 10) + if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) && + WinSdkVersion.has_value()) + windowsSDKLibVersion = *WinSdkVersion; if (sdkMajor >= 8) llvm::sys::path::append(libPath, windowsSDKLibVersion, "um"); return llvm::appendArchToWindowsSDKLibPath(sdkMajor, libPath, getArch(), @@ -567,6 +571,10 @@ bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args, UCRTVersion)) return false; + if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) && + WinSdkVersion.has_value()) + UCRTVersion = *WinSdkVersion; + StringRef ArchName = llvm::archToWindowsSDKArch(getArch()); if (ArchName.empty()) return false; @@ -696,6 +704,9 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, if (llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot, UniversalCRTSdkPath, UCRTVersion)) { + if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) && + WinSdkVersion.has_value()) + UCRTVersion = *WinSdkVersion; AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath, "Include", UCRTVersion, "ucrt"); } @@ -708,6 +719,10 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, if (llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot, WindowsSDKDir, major, windowsSDKIncludeVersion, windowsSDKLibVersion)) { + if (major >= 10) + if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) && + WinSdkVersion.has_value()) + windowsSDKIncludeVersion = windowsSDKLibVersion = *WinSdkVersion; if (major >= 8) { // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10. // Anyway, llvm::sys::path::append is able to manage it. diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index e0fc29879abe..29219662e542 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -559,7 +559,7 @@ void LinkerDriver::detectWinSysRoot(const opt::InputArgList &Args) { WinSysRoot, vcToolChainPath, vsLayout) && (Args.hasArg(OPT_lldignoreenv) || !findVCToolChainViaEnvironment(*VFS, vcToolChainPath, vsLayout)) && - !findVCToolChainViaSetupConfig(*VFS, vcToolChainPath, vsLayout) && + !findVCToolChainViaSetupConfig(*VFS, {}, vcToolChainPath, vsLayout) && !findVCToolChainViaRegistry(vcToolChainPath, vsLayout)) return; diff --git a/llvm/include/llvm/WindowsDriver/MSVCPaths.h b/llvm/include/llvm/WindowsDriver/MSVCPaths.h index d52b33d65169..51ffd6b6bc2c 100644 --- a/llvm/include/llvm/WindowsDriver/MSVCPaths.h +++ b/llvm/include/llvm/WindowsDriver/MSVCPaths.h @@ -90,11 +90,15 @@ bool findVCToolChainViaEnvironment(vfs::FileSystem &VFS, std::string &Path, ToolsetLayout &VSLayout); // Query the Setup Config server for installs, then pick the newest version -// and find its default VC toolchain. +// and find its default VC toolchain. If `VCToolsVersion` is specified, that +// version is preferred over the latest version. +// // This is the preferred way to discover new Visual Studios, as they're no // longer listed in the registry. -bool findVCToolChainViaSetupConfig(vfs::FileSystem &VFS, std::string &Path, - ToolsetLayout &VSLayout); +bool +findVCToolChainViaSetupConfig(vfs::FileSystem &VFS, + std::optional VCToolsVersion, + std::string &Path, ToolsetLayout &VSLayout); // Look in the registry for Visual Studio installs, and use that to get // a toolchain path. VS2017 and newer don't get added to the registry. diff --git a/llvm/lib/ExecutionEngine/Orc/COFFVCRuntimeSupport.cpp b/llvm/lib/ExecutionEngine/Orc/COFFVCRuntimeSupport.cpp index d9316fab2de3..94f696fa2086 100644 --- a/llvm/lib/ExecutionEngine/Orc/COFFVCRuntimeSupport.cpp +++ b/llvm/lib/ExecutionEngine/Orc/COFFVCRuntimeSupport.cpp @@ -160,7 +160,7 @@ COFFVCRuntimeBootstrapper::getMSVCToolchainPath() { if (!findVCToolChainViaCommandLine(*VFS, std::nullopt, std::nullopt, std::nullopt, VCToolChainPath, VSLayout) && !findVCToolChainViaEnvironment(*VFS, VCToolChainPath, VSLayout) && - !findVCToolChainViaSetupConfig(*VFS, VCToolChainPath, VSLayout) && + !findVCToolChainViaSetupConfig(*VFS, {}, VCToolChainPath, VSLayout) && !findVCToolChainViaRegistry(VCToolChainPath, VSLayout)) return make_error("Couldn't find msvc toolchain.", inconvertibleErrorCode()); diff --git a/llvm/lib/WindowsDriver/MSVCPaths.cpp b/llvm/lib/WindowsDriver/MSVCPaths.cpp index 0aae1bb3a774..6e8496da17c8 100644 --- a/llvm/lib/WindowsDriver/MSVCPaths.cpp +++ b/llvm/lib/WindowsDriver/MSVCPaths.cpp @@ -609,8 +609,9 @@ bool findVCToolChainViaEnvironment(vfs::FileSystem &VFS, std::string &Path, return false; } -bool findVCToolChainViaSetupConfig(vfs::FileSystem &VFS, std::string &Path, - ToolsetLayout &VSLayout) { +bool findVCToolChainViaSetupConfig(vfs::FileSystem &VFS, + std::optional VCToolsVersion, + std::string &Path, ToolsetLayout &VSLayout) { #if !defined(USE_MSVC_SETUP_API) return false; #else @@ -677,17 +678,24 @@ bool findVCToolChainViaSetupConfig(vfs::FileSystem &VFS, std::string &Path, std::string VCRootPath; convertWideToUTF8(std::wstring(VCPathWide), VCRootPath); - SmallString<256> ToolsVersionFilePath(VCRootPath); - sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build", - "Microsoft.VCToolsVersion.default.txt"); + std::string ToolsVersion; + if (VCToolsVersion.has_value()) { + ToolsVersion = *VCToolsVersion; + } else { + SmallString<256> ToolsVersionFilePath(VCRootPath); + sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build", + "Microsoft.VCToolsVersion.default.txt"); + + auto ToolsVersionFile = MemoryBuffer::getFile(ToolsVersionFilePath); + if (!ToolsVersionFile) + return false; + + ToolsVersion = ToolsVersionFile->get()->getBuffer().rtrim(); + } - auto ToolsVersionFile = MemoryBuffer::getFile(ToolsVersionFilePath); - if (!ToolsVersionFile) - return false; SmallString<256> ToolchainPath(VCRootPath); - sys::path::append(ToolchainPath, "Tools", "MSVC", - ToolsVersionFile->get()->getBuffer().rtrim()); + sys::path::append(ToolchainPath, "Tools", "MSVC", ToolsVersion); auto Status = VFS.status(ToolchainPath); if (!Status || !Status->isDirectory()) return false;