diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -5753,6 +5753,10 @@
def _SLASH_TP : CLCompileFlag<"TP">, HelpText<"Treat all source files as C++">;
def _SLASH_vctoolsdir : CLJoinedOrSeparate<"vctoolsdir">,
HelpText<"Path to the VCToolChain">, MetaVarName<"
">;
+def _SLASH_winsdkdir : CLJoinedOrSeparate<"winsdkdir">,
+ HelpText<"Path to the Windows SDK">, MetaVarName<"">;
+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.h b/clang/lib/Driver/ToolChains/MSVC.h
--- a/clang/lib/Driver/ToolChains/MSVC.h
+++ b/clang/lib/Driver/ToolChains/MSVC.h
@@ -126,9 +126,10 @@
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/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -81,8 +81,9 @@
}
// 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 VCToolsInstallDir =
@@ -355,13 +356,13 @@
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 @@
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 @@
}
// 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 @@
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 @@
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 @@
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 @@
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/test/Driver/cl-options.c b/clang/test/Driver/cl-options.c
--- 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() { }