diff options
author | Nico Weber <thakis@chromium.org> | 2021-01-26 15:21:12 -0500 |
---|---|---|
committer | Nico Weber <thakis@chromium.org> | 2021-01-27 06:37:51 -0500 |
commit | a5d85cbec58edc447b607f503ca4344e184dbb39 (patch) | |
tree | 5a0fe4effc55c18194eedf89a422462f400c1af2 | |
parent | 00fcc036873164029d30819354fa923b7254cd81 (diff) | |
download | llvm-a5d85cbec58edc447b607f503ca4344e184dbb39.zip llvm-a5d85cbec58edc447b607f503ca4344e184dbb39.tar.gz llvm-a5d85cbec58edc447b607f503ca4344e184dbb39.tar.bz2 |
clang-cl: Add /winsdkdir and /winsdkversion flags
These do for the Windows SDK path what D85998 did for
%VCToolsInstallDir% with /vctoolsdir: Offer a way to set them with an
explicit commandline switch.
With this (and /vctoolsdir), it's possible to compile and link
against hermetic vctools and winsdk directories with:
out/gn/bin/clang-cl win.c -fuse-ld=lld \
/vctoolsdir path/to/VC/Tools/MSVC/14.26.28801 \
/winsdkdir path/to/win_sdk
compared to a long list of -imsvc and /link /libpath: flags.
While here:
- Change the case of the "Include" folder inside the windows sdk
from "include" to "Include" to match on-disk case. Since the
Windows file system is case-insensitive this isn't a behavior
change, it's just a bit cleaner.
- Add libpath tests to the /vctoolsdir
- Add a FIXME about reading env vars for win sdk and ucrt sdk
if these flags aren't present, to match the VCToolsInstallDir
logic
We should also cache all these computed paths in the driver instead
of computing them every time they're queried, but that's for a future
patch.
It'd also be nice to invent a /winsysroot: flag that sets both
/vctoolsdir: and /winsdkdir: to some well-known subdirectory.
That's for a future patch as well.
Differential Revision: https://reviews.llvm.org/D95472
-rw-r--r-- | clang/include/clang/Driver/Options.td | 4 | ||||
-rw-r--r-- | clang/lib/Driver/ToolChains/MSVC.cpp | 80 | ||||
-rw-r--r-- | clang/lib/Driver/ToolChains/MSVC.h | 7 | ||||
-rw-r--r-- | clang/test/Driver/cl-options.c | 10 |
4 files changed, 79 insertions, 22 deletions
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index aa5b429..90f8026 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5753,6 +5753,10 @@ def _SLASH_Tp : CLCompileJoinedOrSeparate<"Tp">, def _SLASH_TP : CLCompileFlag<"TP">, HelpText<"Treat all source files as C++">; def _SLASH_vctoolsdir : CLJoinedOrSeparate<"vctoolsdir">, HelpText<"Path to the VCToolChain">, MetaVarName<"<dir>">; +def _SLASH_winsdkdir : CLJoinedOrSeparate<"winsdkdir">, + HelpText<"Path to the Windows SDK">, MetaVarName<"<dir>">; +def _SLASH_winsdkversion : CLJoinedOrSeparate<"winsdkversion">, + HelpText<"Full version of the Windows SDK">; def _SLASH_volatile_iso : Option<["/", "-"], "volatile:iso", KIND_FLAG>, Group<_SLASH_volatile_Group>, Flags<[CLOption, NoXarchOption]>, HelpText<"Volatile loads and stores have standard semantics">; diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index f4b7a57e..6ab2fd6 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -81,8 +81,9 @@ findVCToolChainViaCommandLine(const ArgList &Args, std::string &Path, } // Check various environment variables to try and find a toolchain. -static bool findVCToolChainViaEnvironment(std::string &Path, - MSVCToolChain::ToolsetLayout &VSLayout) { +static bool +findVCToolChainViaEnvironment(std::string &Path, + MSVCToolChain::ToolsetLayout &VSLayout) { // These variables are typically set by vcvarsall.bat // when launching a developer command prompt. if (llvm::Optional<std::string> VCToolsInstallDir = @@ -355,13 +356,13 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (TC.useUniversalCRT()) { std::string UniversalCRTLibPath; - if (TC.getUniversalCRTLibraryPath(UniversalCRTLibPath)) + if (TC.getUniversalCRTLibraryPath(Args, UniversalCRTLibPath)) CmdArgs.push_back( Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath)); } std::string WindowsSdkLibPath; - if (TC.getWindowsSDKLibraryPath(WindowsSdkLibPath)) + if (TC.getWindowsSDKLibraryPath(Args, WindowsSdkLibPath)) CmdArgs.push_back( Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath)); } @@ -1088,12 +1089,43 @@ static bool getWindows10SDKVersionFromPath(const std::string &SDKPath, return !SDKVersion.empty(); } +static bool getWindowsSDKDirViaCommandLine(const ArgList &Args, + std::string &Path, int &Major, + std::string &Version) { + if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir)) { + // Don't validate the input; trust the value supplied by the user. + // The motivation is to prevent unnecessary file and registry access. + Path = A->getValue(); + if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion)) { + StringRef WinSdkVersion = A->getValue(); + Version = WinSdkVersion.str(); + if (WinSdkVersion.consumeInteger(10, Major)) + return false; + if (!(WinSdkVersion.empty() || WinSdkVersion.startswith("."))) + return false; + } else if (getWindows10SDKVersionFromPath(Path, Version)) { + Major = 10; + } + return true; + } + return false; +} + /// Get Windows SDK installation directory. -static bool getWindowsSDKDir(std::string &Path, int &Major, +static bool getWindowsSDKDir(const ArgList &Args, std::string &Path, int &Major, std::string &WindowsSDKIncludeVersion, std::string &WindowsSDKLibVersion) { - std::string RegistrySDKVersion; + // Trust /winsdkdir: and /winsdkversion: if present. + if (getWindowsSDKDirViaCommandLine( + Args, Path, Major, WindowsSDKIncludeVersion)) { + WindowsSDKLibVersion = WindowsSDKIncludeVersion; + return true; + } + + // FIXME: Try env vars (%WindowsSdkDir%, %UCRTVersion%) before going to registry. + // Try the Windows registry. + std::string RegistrySDKVersion; if (!getSystemRegistryString( "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", "InstallationFolder", Path, &RegistrySDKVersion)) @@ -1133,14 +1165,15 @@ static bool getWindowsSDKDir(std::string &Path, int &Major, } // Gets the library path required to link against the Windows SDK. -bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const { +bool MSVCToolChain::getWindowsSDKLibraryPath( + const ArgList &Args, std::string &path) const { std::string sdkPath; int sdkMajor = 0; std::string windowsSDKIncludeVersion; std::string windowsSDKLibVersion; path.clear(); - if (!getWindowsSDKDir(sdkPath, sdkMajor, windowsSDKIncludeVersion, + if (!getWindowsSDKDir(Args, sdkPath, sdkMajor, windowsSDKIncludeVersion, windowsSDKLibVersion)) return false; @@ -1178,7 +1211,17 @@ bool MSVCToolChain::useUniversalCRT() const { return !llvm::sys::fs::exists(TestPath); } -static bool getUniversalCRTSdkDir(std::string &Path, std::string &UCRTVersion) { +static bool getUniversalCRTSdkDir(const ArgList &Args, std::string &Path, + std::string &UCRTVersion) { + // If /winsdkdir: is passed, use it as location for the UCRT too. + // FIXME: Should there be a dedicated /ucrtdir: to override /winsdkdir:? + int Major; + if (getWindowsSDKDirViaCommandLine(Args, Path, Major, UCRTVersion)) + return true; + + // FIXME: Try env vars (%UniversalCRTSdkDir%, %UCRTVersion%) before going to + // registry. + // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry // for the specific key "KitsRoot10". So do we. if (!getSystemRegistryString( @@ -1189,12 +1232,13 @@ static bool getUniversalCRTSdkDir(std::string &Path, std::string &UCRTVersion) { return getWindows10SDKVersionFromPath(Path, UCRTVersion); } -bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const { +bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args, + std::string &Path) const { std::string UniversalCRTSdkPath; std::string UCRTVersion; Path.clear(); - if (!getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) + if (!getUniversalCRTSdkDir(Args, UniversalCRTSdkPath, UCRTVersion)) return false; StringRef ArchName = llvmArchToWindowsSDKArch(getArch()); @@ -1304,7 +1348,7 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, if (useUniversalCRT()) { std::string UniversalCRTSdkPath; std::string UCRTVersion; - if (getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) { + if (getUniversalCRTSdkDir(DriverArgs, UniversalCRTSdkPath, UCRTVersion)) { AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath, "Include", UCRTVersion, "ucrt"); } @@ -1314,23 +1358,23 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, int major; std::string windowsSDKIncludeVersion; std::string windowsSDKLibVersion; - if (getWindowsSDKDir(WindowsSDKDir, major, windowsSDKIncludeVersion, - windowsSDKLibVersion)) { + if (getWindowsSDKDir(DriverArgs, WindowsSDKDir, major, + windowsSDKIncludeVersion, windowsSDKLibVersion)) { if (major >= 8) { // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10. // Anyway, llvm::sys::path::append is able to manage it. AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, - "include", windowsSDKIncludeVersion, + "Include", windowsSDKIncludeVersion, "shared"); AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, - "include", windowsSDKIncludeVersion, + "Include", windowsSDKIncludeVersion, "um"); AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, - "include", windowsSDKIncludeVersion, + "Include", windowsSDKIncludeVersion, "winrt"); } else { AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, - "include"); + "Include"); } } diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h index dba99ed..29abf0c 100644 --- a/clang/lib/Driver/ToolChains/MSVC.h +++ b/clang/lib/Driver/ToolChains/MSVC.h @@ -126,9 +126,10 @@ public: void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - bool getWindowsSDKLibraryPath(std::string &path) const; - /// Check if Universal CRT should be used if available - bool getUniversalCRTLibraryPath(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; VersionTuple computeMSVCVersion(const Driver *D, diff --git a/clang/test/Driver/cl-options.c b/clang/test/Driver/cl-options.c index 4b6d71e..487cbf0 100644 --- a/clang/test/Driver/cl-options.c +++ b/clang/test/Driver/cl-options.c @@ -696,8 +696,16 @@ // VCTOOLSDIR: "-triple" "{{[a-zA-Z0-9_-]*}}-pc-windows-msvc19.11.0" // Validate that built-in include paths are based on the supplied path -// RUN: %clang_cl -vctoolsdir "/fake" -### -- %s 2>&1 | FileCheck %s --check-prefix FAKEDIR +// RUN: %clang_cl -vctoolsdir "/fake" -winsdkdir "/foo" -winsdkversion 10.0.12345.0 -### -- %s 2>&1 | FileCheck %s --check-prefix FAKEDIR // FAKEDIR: "-internal-isystem" "/fake{{/|\\\\}}include" // FAKEDIR: "-internal-isystem" "/fake{{/|\\\\}}atlmfc{{/|\\\\}}include" +// FAKEDIR: "-internal-isystem" "/foo{{/|\\\\}}Include{{/|\\\\}}10.0.12345.0{{/|\\\\}}ucrt" +// FAKEDIR: "-internal-isystem" "/foo{{/|\\\\}}Include{{/|\\\\}}10.0.12345.0{{/|\\\\}}shared" +// FAKEDIR: "-internal-isystem" "/foo{{/|\\\\}}Include{{/|\\\\}}10.0.12345.0{{/|\\\\}}um" +// FAKEDIR: "-internal-isystem" "/foo{{/|\\\\}}Include{{/|\\\\}}10.0.12345.0{{/|\\\\}}winrt" +// FAKEDIR: "-libpath:/fake{{/|\\\\}}lib{{/|\\\\}} +// FAKEDIR: "-libpath:/fake{{/|\\\\}}atlmfc{{/|\\\\}}lib{{/|\\\\}} +// FAKEDIR: "-libpath:/foo{{/|\\\\}}Lib{{/|\\\\}}10.0.12345.0{{/|\\\\}}ucrt +// FAKEDIR: "-libpath:/foo{{/|\\\\}}Lib{{/|\\\\}}10.0.12345.0{{/|\\\\}}um void f() { } |