Skip to content

Commit a5d85cb

Browse files
committed
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
1 parent 00fcc03 commit a5d85cb

File tree

4 files changed

+79
-22
lines changed

4 files changed

+79
-22
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5753,6 +5753,10 @@ def _SLASH_Tp : CLCompileJoinedOrSeparate<"Tp">,
57535753
def _SLASH_TP : CLCompileFlag<"TP">, HelpText<"Treat all source files as C++">;
57545754
def _SLASH_vctoolsdir : CLJoinedOrSeparate<"vctoolsdir">,
57555755
HelpText<"Path to the VCToolChain">, MetaVarName<"<dir>">;
5756+
def _SLASH_winsdkdir : CLJoinedOrSeparate<"winsdkdir">,
5757+
HelpText<"Path to the Windows SDK">, MetaVarName<"<dir>">;
5758+
def _SLASH_winsdkversion : CLJoinedOrSeparate<"winsdkversion">,
5759+
HelpText<"Full version of the Windows SDK">;
57565760
def _SLASH_volatile_iso : Option<["/", "-"], "volatile:iso", KIND_FLAG>,
57575761
Group<_SLASH_volatile_Group>, Flags<[CLOption, NoXarchOption]>,
57585762
HelpText<"Volatile loads and stores have standard semantics">;

clang/lib/Driver/ToolChains/MSVC.cpp

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,9 @@ findVCToolChainViaCommandLine(const ArgList &Args, std::string &Path,
8181
}
8282

8383
// Check various environment variables to try and find a toolchain.
84-
static bool findVCToolChainViaEnvironment(std::string &Path,
85-
MSVCToolChain::ToolsetLayout &VSLayout) {
84+
static bool
85+
findVCToolChainViaEnvironment(std::string &Path,
86+
MSVCToolChain::ToolsetLayout &VSLayout) {
8687
// These variables are typically set by vcvarsall.bat
8788
// when launching a developer command prompt.
8889
if (llvm::Optional<std::string> VCToolsInstallDir =
@@ -355,13 +356,13 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
355356

356357
if (TC.useUniversalCRT()) {
357358
std::string UniversalCRTLibPath;
358-
if (TC.getUniversalCRTLibraryPath(UniversalCRTLibPath))
359+
if (TC.getUniversalCRTLibraryPath(Args, UniversalCRTLibPath))
359360
CmdArgs.push_back(
360361
Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath));
361362
}
362363

363364
std::string WindowsSdkLibPath;
364-
if (TC.getWindowsSDKLibraryPath(WindowsSdkLibPath))
365+
if (TC.getWindowsSDKLibraryPath(Args, WindowsSdkLibPath))
365366
CmdArgs.push_back(
366367
Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
367368
}
@@ -1088,12 +1089,43 @@ static bool getWindows10SDKVersionFromPath(const std::string &SDKPath,
10881089
return !SDKVersion.empty();
10891090
}
10901091

1092+
static bool getWindowsSDKDirViaCommandLine(const ArgList &Args,
1093+
std::string &Path, int &Major,
1094+
std::string &Version) {
1095+
if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir)) {
1096+
// Don't validate the input; trust the value supplied by the user.
1097+
// The motivation is to prevent unnecessary file and registry access.
1098+
Path = A->getValue();
1099+
if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion)) {
1100+
StringRef WinSdkVersion = A->getValue();
1101+
Version = WinSdkVersion.str();
1102+
if (WinSdkVersion.consumeInteger(10, Major))
1103+
return false;
1104+
if (!(WinSdkVersion.empty() || WinSdkVersion.startswith(".")))
1105+
return false;
1106+
} else if (getWindows10SDKVersionFromPath(Path, Version)) {
1107+
Major = 10;
1108+
}
1109+
return true;
1110+
}
1111+
return false;
1112+
}
1113+
10911114
/// Get Windows SDK installation directory.
1092-
static bool getWindowsSDKDir(std::string &Path, int &Major,
1115+
static bool getWindowsSDKDir(const ArgList &Args, std::string &Path, int &Major,
10931116
std::string &WindowsSDKIncludeVersion,
10941117
std::string &WindowsSDKLibVersion) {
1095-
std::string RegistrySDKVersion;
1118+
// Trust /winsdkdir: and /winsdkversion: if present.
1119+
if (getWindowsSDKDirViaCommandLine(
1120+
Args, Path, Major, WindowsSDKIncludeVersion)) {
1121+
WindowsSDKLibVersion = WindowsSDKIncludeVersion;
1122+
return true;
1123+
}
1124+
1125+
// FIXME: Try env vars (%WindowsSdkDir%, %UCRTVersion%) before going to registry.
1126+
10961127
// Try the Windows registry.
1128+
std::string RegistrySDKVersion;
10971129
if (!getSystemRegistryString(
10981130
"SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
10991131
"InstallationFolder", Path, &RegistrySDKVersion))
@@ -1133,14 +1165,15 @@ static bool getWindowsSDKDir(std::string &Path, int &Major,
11331165
}
11341166

11351167
// Gets the library path required to link against the Windows SDK.
1136-
bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const {
1168+
bool MSVCToolChain::getWindowsSDKLibraryPath(
1169+
const ArgList &Args, std::string &path) const {
11371170
std::string sdkPath;
11381171
int sdkMajor = 0;
11391172
std::string windowsSDKIncludeVersion;
11401173
std::string windowsSDKLibVersion;
11411174

11421175
path.clear();
1143-
if (!getWindowsSDKDir(sdkPath, sdkMajor, windowsSDKIncludeVersion,
1176+
if (!getWindowsSDKDir(Args, sdkPath, sdkMajor, windowsSDKIncludeVersion,
11441177
windowsSDKLibVersion))
11451178
return false;
11461179

@@ -1178,7 +1211,17 @@ bool MSVCToolChain::useUniversalCRT() const {
11781211
return !llvm::sys::fs::exists(TestPath);
11791212
}
11801213

1181-
static bool getUniversalCRTSdkDir(std::string &Path, std::string &UCRTVersion) {
1214+
static bool getUniversalCRTSdkDir(const ArgList &Args, std::string &Path,
1215+
std::string &UCRTVersion) {
1216+
// If /winsdkdir: is passed, use it as location for the UCRT too.
1217+
// FIXME: Should there be a dedicated /ucrtdir: to override /winsdkdir:?
1218+
int Major;
1219+
if (getWindowsSDKDirViaCommandLine(Args, Path, Major, UCRTVersion))
1220+
return true;
1221+
1222+
// FIXME: Try env vars (%UniversalCRTSdkDir%, %UCRTVersion%) before going to
1223+
// registry.
1224+
11821225
// vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry
11831226
// for the specific key "KitsRoot10". So do we.
11841227
if (!getSystemRegistryString(
@@ -1189,12 +1232,13 @@ static bool getUniversalCRTSdkDir(std::string &Path, std::string &UCRTVersion) {
11891232
return getWindows10SDKVersionFromPath(Path, UCRTVersion);
11901233
}
11911234

1192-
bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const {
1235+
bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args,
1236+
std::string &Path) const {
11931237
std::string UniversalCRTSdkPath;
11941238
std::string UCRTVersion;
11951239

11961240
Path.clear();
1197-
if (!getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion))
1241+
if (!getUniversalCRTSdkDir(Args, UniversalCRTSdkPath, UCRTVersion))
11981242
return false;
11991243

12001244
StringRef ArchName = llvmArchToWindowsSDKArch(getArch());
@@ -1304,7 +1348,7 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
13041348
if (useUniversalCRT()) {
13051349
std::string UniversalCRTSdkPath;
13061350
std::string UCRTVersion;
1307-
if (getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) {
1351+
if (getUniversalCRTSdkDir(DriverArgs, UniversalCRTSdkPath, UCRTVersion)) {
13081352
AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath,
13091353
"Include", UCRTVersion, "ucrt");
13101354
}
@@ -1314,23 +1358,23 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
13141358
int major;
13151359
std::string windowsSDKIncludeVersion;
13161360
std::string windowsSDKLibVersion;
1317-
if (getWindowsSDKDir(WindowsSDKDir, major, windowsSDKIncludeVersion,
1318-
windowsSDKLibVersion)) {
1361+
if (getWindowsSDKDir(DriverArgs, WindowsSDKDir, major,
1362+
windowsSDKIncludeVersion, windowsSDKLibVersion)) {
13191363
if (major >= 8) {
13201364
// Note: windowsSDKIncludeVersion is empty for SDKs prior to v10.
13211365
// Anyway, llvm::sys::path::append is able to manage it.
13221366
AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
1323-
"include", windowsSDKIncludeVersion,
1367+
"Include", windowsSDKIncludeVersion,
13241368
"shared");
13251369
AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
1326-
"include", windowsSDKIncludeVersion,
1370+
"Include", windowsSDKIncludeVersion,
13271371
"um");
13281372
AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
1329-
"include", windowsSDKIncludeVersion,
1373+
"Include", windowsSDKIncludeVersion,
13301374
"winrt");
13311375
} else {
13321376
AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
1333-
"include");
1377+
"Include");
13341378
}
13351379
}
13361380

clang/lib/Driver/ToolChains/MSVC.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,10 @@ class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain {
126126
void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs,
127127
llvm::opt::ArgStringList &CC1Args) const override;
128128

129-
bool getWindowsSDKLibraryPath(std::string &path) const;
130-
/// Check if Universal CRT should be used if available
131-
bool getUniversalCRTLibraryPath(std::string &path) const;
129+
bool getWindowsSDKLibraryPath(
130+
const llvm::opt::ArgList &Args, std::string &path) const;
131+
bool getUniversalCRTLibraryPath(const llvm::opt::ArgList &Args,
132+
std::string &path) const;
132133
bool useUniversalCRT() const;
133134
VersionTuple
134135
computeMSVCVersion(const Driver *D,

clang/test/Driver/cl-options.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -696,8 +696,16 @@
696696
// VCTOOLSDIR: "-triple" "{{[a-zA-Z0-9_-]*}}-pc-windows-msvc19.11.0"
697697

698698
// Validate that built-in include paths are based on the supplied path
699-
// RUN: %clang_cl -vctoolsdir "/fake" -### -- %s 2>&1 | FileCheck %s --check-prefix FAKEDIR
699+
// RUN: %clang_cl -vctoolsdir "/fake" -winsdkdir "/foo" -winsdkversion 10.0.12345.0 -### -- %s 2>&1 | FileCheck %s --check-prefix FAKEDIR
700700
// FAKEDIR: "-internal-isystem" "/fake{{/|\\\\}}include"
701701
// FAKEDIR: "-internal-isystem" "/fake{{/|\\\\}}atlmfc{{/|\\\\}}include"
702+
// FAKEDIR: "-internal-isystem" "/foo{{/|\\\\}}Include{{/|\\\\}}10.0.12345.0{{/|\\\\}}ucrt"
703+
// FAKEDIR: "-internal-isystem" "/foo{{/|\\\\}}Include{{/|\\\\}}10.0.12345.0{{/|\\\\}}shared"
704+
// FAKEDIR: "-internal-isystem" "/foo{{/|\\\\}}Include{{/|\\\\}}10.0.12345.0{{/|\\\\}}um"
705+
// FAKEDIR: "-internal-isystem" "/foo{{/|\\\\}}Include{{/|\\\\}}10.0.12345.0{{/|\\\\}}winrt"
706+
// FAKEDIR: "-libpath:/fake{{/|\\\\}}lib{{/|\\\\}}
707+
// FAKEDIR: "-libpath:/fake{{/|\\\\}}atlmfc{{/|\\\\}}lib{{/|\\\\}}
708+
// FAKEDIR: "-libpath:/foo{{/|\\\\}}Lib{{/|\\\\}}10.0.12345.0{{/|\\\\}}ucrt
709+
// FAKEDIR: "-libpath:/foo{{/|\\\\}}Lib{{/|\\\\}}10.0.12345.0{{/|\\\\}}um
702710

703711
void f() { }

0 commit comments

Comments
 (0)