Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -5762,10 +5762,15 @@
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_vctoolsversion : CLJoinedOrSeparate<"vctoolsversion">,
+ HelpText<"For use with /winsysroot, defaults to newest found">;
def _SLASH_winsdkdir : CLJoinedOrSeparate<"winsdkdir">,
HelpText<"Path to the Windows SDK">, MetaVarName<"">;
def _SLASH_winsdkversion : CLJoinedOrSeparate<"winsdkversion">,
- HelpText<"Full version of the Windows SDK">;
+ HelpText<"Full version of the Windows SDK, defaults to newest found">;
+def _SLASH_winsysroot : CLJoinedOrSeparate<"winsysroot">,
+ HelpText<"Same as /vctoolsdir /VC/Tools/MSVC/ /winsdkdir /Windows Kits/10">,
+ MetaVarName<"">;
def _SLASH_volatile_iso : Option<["/", "-"], "volatile:iso", KIND_FLAG>,
Group<_SLASH_volatile_Group>, Flags<[CLOption, NoXarchOption]>,
HelpText<"Volatile loads and stores have standard semantics">;
Index: clang/lib/Driver/ToolChains/MSVC.cpp
===================================================================
--- clang/lib/Driver/ToolChains/MSVC.cpp
+++ clang/lib/Driver/ToolChains/MSVC.cpp
@@ -66,14 +66,49 @@
static bool getSystemRegistryString(const char *keyPath, const char *valueName,
std::string &value, std::string *phValue);
+static bool getHighestNumericTupleInDirectory(StringRef Directory, std::string &Highest) {
+ Highest.clear();
+ llvm::VersionTuple HighestTuple;
+
+ std::error_code EC;
+ for (llvm::sys::fs::directory_iterator DirIt(Directory, EC), DirEnd;
+ DirIt != DirEnd && !EC; DirIt.increment(EC)) {
+ if (!llvm::sys::fs::is_directory(DirIt->path()))
+ continue;
+ StringRef CandidateName = llvm::sys::path::filename(DirIt->path());
+ llvm::VersionTuple Tuple;
+ if (Tuple.tryParse(CandidateName)) // tryParse() returns true on error.
+ continue;
+ if (Tuple > HighestTuple) {
+ HighestTuple = Tuple;
+ Highest = CandidateName.str();
+ }
+ }
+
+ return !Highest.empty();
+}
+
// Check command line arguments to try and find a toolchain.
static bool
findVCToolChainViaCommandLine(const ArgList &Args, std::string &Path,
MSVCToolChain::ToolsetLayout &VSLayout) {
// Don't validate the input; trust the value supplied by the user.
// The primary motivation is to prevent unnecessary file and registry access.
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir)) {
- Path = A->getValue();
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir,
+ options::OPT__SLASH_winsysroot)) {
+ if (A->getOption().getID() == options::OPT__SLASH_winsysroot) {
+ llvm::SmallString<128> ToolsPath(A->getValue());
+ llvm::sys::path::append(ToolsPath, "VC", "Tools", "MSVC");
+ std::string VCToolsVersion;
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion))
+ VCToolsVersion = A->getValue();
+ else
+ getHighestNumericTupleInDirectory(ToolsPath, VCToolsVersion);
+ llvm::sys::path::append(ToolsPath, VCToolsVersion);
+ Path = std::string(ToolsPath.str());
+ } else {
+ Path = A->getValue();
+ }
VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
return true;
}
@@ -345,7 +380,8 @@
// they're doing. If the user passes /vctoolsdir or /winsdkdir, trust that
// over env vars.
if (!llvm::sys::Process::GetEnv("LIB") ||
- Args.getLastArg(options::OPT__SLASH_vctoolsdir)) {
+ Args.getLastArg(options::OPT__SLASH_vctoolsdir,
+ options::OPT__SLASH_winsysroot)) {
CmdArgs.push_back(Args.MakeArgString(
Twine("-libpath:") +
TC.getSubDirectoryPath(
@@ -356,7 +392,8 @@
"atlmfc")));
}
if (!llvm::sys::Process::GetEnv("LIB") ||
- Args.getLastArg(options::OPT__SLASH_winsdkdir)) {
+ Args.getLastArg(options::OPT__SLASH_winsdkdir,
+ options::OPT__SLASH_winsysroot)) {
if (TC.useUniversalCRT()) {
std::string UniversalCRTLibPath;
if (TC.getUniversalCRTLibraryPath(Args, UniversalCRTLibPath))
@@ -1074,37 +1111,38 @@
std::error_code EC;
llvm::SmallString<128> IncludePath(SDKPath);
llvm::sys::path::append(IncludePath, "Include");
- for (llvm::sys::fs::directory_iterator DirIt(IncludePath, EC), DirEnd;
- DirIt != DirEnd && !EC; DirIt.increment(EC)) {
- if (!llvm::sys::fs::is_directory(DirIt->path()))
- continue;
- StringRef CandidateName = llvm::sys::path::filename(DirIt->path());
- // If WDK is installed, there could be subfolders like "wdf" in the
- // "Include" directory.
- // Allow only directories which names start with "10.".
- if (!CandidateName.startswith("10."))
- continue;
- if (CandidateName > SDKVersion)
- SDKVersion = std::string(CandidateName);
- }
-
- return !SDKVersion.empty();
+ return getHighestNumericTupleInDirectory(IncludePath, SDKVersion);
}
static bool getWindowsSDKDirViaCommandLine(const ArgList &Args,
std::string &Path, int &Major,
std::string &Version) {
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir)) {
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir,
+ options::OPT__SLASH_winsysroot)) {
// 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;
+ llvm::VersionTuple SDKVersion;
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion))
+ SDKVersion.tryParse(A->getValue());
+
+ if (A->getOption().getID() == options::OPT__SLASH_winsysroot) {
+ llvm::SmallString<128> SDKPath(A->getValue());
+ llvm::sys::path::append(SDKPath, "Windows Kits");
+ if (!SDKVersion.empty()) {
+ llvm::sys::path::append(SDKPath, Twine(SDKVersion.getMajor()));
+ } else {
+ std::string SDKVersion;
+ if (getHighestNumericTupleInDirectory(SDKPath, SDKVersion))
+ llvm::sys::path::append(SDKPath, SDKVersion);
+ }
+ Path = std::string(SDKPath.str());
+ } else {
+ Path = A->getValue();
+ }
+
+ if (!SDKVersion.empty()) {
+ Major = SDKVersion.getMajor();
+ Version = SDKVersion.getAsString();
} else if (getWindows10SDKVersionFromPath(Path, Version)) {
Major = 10;
}
@@ -1326,7 +1364,8 @@
// Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat.
// Skip if the user expressly set a vctoolsdir
- if (!DriverArgs.getLastArg(options::OPT__SLASH_vctoolsdir)) {
+ if (!DriverArgs.getLastArg(options::OPT__SLASH_vctoolsdir,
+ options::OPT__SLASH_winsysroot)) {
if (llvm::Optional cl_include_dir =
llvm::sys::Process::GetEnv("INCLUDE")) {
SmallVector Dirs;