Update clang-cl driver for MSVC 2017.
2017 changes the way you find an installed copy of
Visual Studio as well as its internal directory layout.
As a result, clang-cl was unable to find VS2017 even
when you had run vcvarsall to set up a toolchain
environment. This patch updates everything for 2017
and cleans up the way we handle a tiered search a la
environment -> installation -> PATH for which copy
of Visual Studio to bind to.
Patch originally by Hamza Sood, with some fixups for landing.
Differential Revision: https://reviews.llvm.org/D30758
llvm-svn: 297851
diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp
index 7996627..ce8e1b2 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -7,9 +7,9 @@
//
//===----------------------------------------------------------------------===//
-#include "Darwin.h"
#include "MSVC.h"
#include "CommonArgs.h"
+#include "Darwin.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/Compilation.h"
@@ -25,6 +25,8 @@
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include <cstdio>
@@ -42,6 +44,18 @@
#define NOMINMAX
#endif
#include <windows.h>
+
+// Make sure this comes before MSVCSetupApi.h
+#include <comdef.h>
+
+#include "MSVCSetupApi.h"
+#include "llvm/Support/COM.h"
+_COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration));
+_COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2));
+_COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper));
+_COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances));
+_COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance));
+_COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2));
#endif
using namespace clang::driver;
@@ -50,24 +64,232 @@
using namespace clang;
using namespace llvm::opt;
+// Defined below.
+// Forward declare this so there aren't too many things above the constructor.
+static bool getSystemRegistryString(const char *keyPath, const char *valueName,
+ std::string &value, std::string *phValue);
+
+// Check various environment variables to try and find a toolchain.
+static bool findVCToolChainViaEnvironment(std::string &Path,
+ bool &IsVS2017OrNewer) {
+ // These variables are typically set by vcvarsall.bat
+ // when launching a developer command prompt.
+ if (llvm::Optional<std::string> VCToolsInstallDir =
+ llvm::sys::Process::GetEnv("VCToolsInstallDir")) {
+ // This is only set by newer Visual Studios, and it leads straight to
+ // the toolchain directory.
+ Path = std::move(*VCToolsInstallDir);
+ IsVS2017OrNewer = true;
+ return true;
+ }
+ if (llvm::Optional<std::string> VCInstallDir =
+ llvm::sys::Process::GetEnv("VCINSTALLDIR")) {
+ // If the previous variable isn't set but this one is, then we've found
+ // an older Visual Studio. This variable is set by newer Visual Studios too,
+ // so this check has to appear second.
+ // In older Visual Studios, the VC directory is the toolchain.
+ Path = std::move(*VCInstallDir);
+ IsVS2017OrNewer = false;
+ return true;
+ }
+
+ // We couldn't find any VC environment variables. Let's walk through PATH and
+ // see if it leads us to a VC toolchain bin directory. If it does, pick the
+ // first one that we find.
+ if (llvm::Optional<std::string> PathEnv =
+ llvm::sys::Process::GetEnv("PATH")) {
+ llvm::SmallVector<llvm::StringRef, 8> PathEntries;
+ llvm::StringRef(*PathEnv).split(PathEntries, llvm::sys::EnvPathSeparator);
+ for (llvm::StringRef PathEntry : PathEntries) {
+ if (PathEntry.empty())
+ continue;
+
+ llvm::SmallString<256> ExeTestPath;
+
+ // If cl.exe doesn't exist, then this definitely isn't a VC toolchain.
+ ExeTestPath = PathEntry;
+ llvm::sys::path::append(ExeTestPath, "cl.exe");
+ if (!llvm::sys::fs::exists(ExeTestPath))
+ continue;
+
+ // cl.exe existing isn't a conclusive test for a VC toolchain; clang also
+ // has a cl.exe. So let's check for link.exe too.
+ ExeTestPath = PathEntry;
+ llvm::sys::path::append(ExeTestPath, "link.exe");
+ if (!llvm::sys::fs::exists(ExeTestPath))
+ continue;
+
+ // whatever/VC/bin --> old toolchain, VC dir is toolchain dir.
+ if (llvm::sys::path::filename(PathEntry) == "bin") {
+ llvm::StringRef ParentPath = llvm::sys::path::parent_path(PathEntry);
+ if (llvm::sys::path::filename(ParentPath) == "VC") {
+ Path = ParentPath;
+ IsVS2017OrNewer = false;
+ return true;
+ }
+
+ } else {
+ // This could be a new (>=VS2017) toolchain. If it is, we should find
+ // path components with these prefixes when walking backwards through
+ // the path.
+ // Note: empty strings match anything.
+ llvm::StringRef ExpectedPrefixes[] = {"", "Host", "bin", "",
+ "MSVC", "Tools", "VC"};
+
+ auto It = llvm::sys::path::rbegin(PathEntry);
+ auto End = llvm::sys::path::rend(PathEntry);
+ for (llvm::StringRef Prefix : ExpectedPrefixes) {
+ if (It == End)
+ goto NotAToolChain;
+ if (!It->startswith(Prefix))
+ goto NotAToolChain;
+ ++It;
+ }
+
+ // We've found a new toolchain!
+ // Back up 3 times (/bin/Host/arch) to get the root path.
+ llvm::StringRef ToolChainPath(PathEntry);
+ for (int i = 0; i < 3; ++i)
+ ToolChainPath = llvm::sys::path::parent_path(ToolChainPath);
+
+ Path = ToolChainPath;
+ IsVS2017OrNewer = true;
+ return true;
+ }
+
+ NotAToolChain:
+ continue;
+ }
+ }
+ return false;
+}
+
+// Query the Setup Config server for installs, then pick the newest version
+// and find its default VC toolchain.
+// This is the preferred way to discover new Visual Studios, as they're no
+// longer listed in the registry.
+static bool findVCToolChainViaSetupConfig(std::string &Path,
+ bool &IsVS2017OrNewer) {
+#if !defined(USE_WIN32)
+ return false;
+#else
+ // FIXME: This really should be done once in the top-level program's main
+ // function, as it may have already been initialized with a different
+ // threading model otherwise.
+ llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::SingleThreaded);
+ HRESULT HR;
+
+ // _com_ptr_t will throw a _com_error if a COM calls fail.
+ // The LLVM coding standards forbid exception handling, so we'll have to
+ // stop them from being thrown in the first place.
+ // The destructor will put the regular error handler back when we leave
+ // this scope.
+ struct SuppressCOMErrorsRAII {
+ static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {}
+
+ SuppressCOMErrorsRAII() { _set_com_error_handler(handler); }
+
+ ~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); }
+
+ } COMErrorSuppressor;
+
+ ISetupConfigurationPtr Query;
+ HR = Query.CreateInstance(__uuidof(SetupConfiguration));
+ if (FAILED(HR))
+ return false;
+
+ IEnumSetupInstancesPtr EnumInstances;
+ HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances);
+ if (FAILED(HR))
+ return false;
+
+ ISetupInstancePtr Instance;
+ HR = EnumInstances->Next(1, &Instance, nullptr);
+ if (HR != S_OK)
+ return false;
+
+ ISetupInstancePtr NewestInstance;
+ Optional<uint64_t> NewestVersionNum;
+ do {
+ bstr_t VersionString;
+ uint64_t VersionNum;
+ HR = Instance->GetInstallationVersion(VersionString.GetAddress());
+ if (FAILED(HR))
+ continue;
+ HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum);
+ if (FAILED(HR))
+ continue;
+ if (!NewestVersionNum || (VersionNum > NewestVersionNum)) {
+ NewestInstance = Instance;
+ NewestVersionNum = VersionNum;
+ }
+ } while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK);
+
+ if (!NewestInstance)
+ return false;
+
+ bstr_t VCPathWide;
+ HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress());
+ if (FAILED(HR))
+ return false;
+
+ std::string VCRootPath;
+ llvm::convertWideToUTF8(std::wstring(VCPathWide), VCRootPath);
+
+ llvm::SmallString<256> ToolsVersionFilePath(VCRootPath);
+ llvm::sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build",
+ "Microsoft.VCToolsVersion.default.txt");
+
+ auto ToolsVersionFile = llvm::MemoryBuffer::getFile(ToolsVersionFilePath);
+ if (!ToolsVersionFile)
+ return false;
+
+ llvm::SmallString<256> ToolchainPath(VCRootPath);
+ llvm::sys::path::append(ToolchainPath, "Tools", "MSVC",
+ ToolsVersionFile->get()->getBuffer().rtrim());
+ if (!llvm::sys::fs::is_directory(ToolchainPath))
+ return false;
+
+ Path = ToolchainPath.str();
+ IsVS2017OrNewer = true;
+ return true;
+#endif
+}
+
+// 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.
+// So if we find something here, we know that it's an older version.
+static bool findVCToolChainViaRegistry(std::string &Path,
+ bool &IsVS2017OrNewer) {
+ std::string VSInstallPath;
+ if (getSystemRegistryString(R"(SOFTWARE\Microsoft\VisualStudio\$VERSION)",
+ "InstallDir", VSInstallPath, nullptr) ||
+ getSystemRegistryString(R"(SOFTWARE\Microsoft\VCExpress\$VERSION)",
+ "InstallDir", VSInstallPath, nullptr)) {
+ if (!VSInstallPath.empty()) {
+ llvm::SmallString<256> VCPath(llvm::StringRef(
+ VSInstallPath.c_str(), VSInstallPath.find(R"(\Common7\IDE)")));
+ llvm::sys::path::append(VCPath, "VC");
+
+ Path = VCPath.str();
+ IsVS2017OrNewer = false;
+ return true;
+ }
+ }
+ return false;
+}
+
// Try to find Exe from a Visual Studio distribution. This first tries to find
// an installed copy of Visual Studio and, failing that, looks in the PATH,
// making sure that whatever executable that's found is not a same-named exe
// from clang itself to prevent clang from falling back to itself.
static std::string FindVisualStudioExecutable(const ToolChain &TC,
- const char *Exe,
- const char *ClangProgramPath) {
+ const char *Exe) {
const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);
- std::string visualStudioBinDir;
- if (MSVC.getVisualStudioBinariesFolder(ClangProgramPath,
- visualStudioBinDir)) {
- SmallString<128> FilePath(visualStudioBinDir);
- llvm::sys::path::append(FilePath, Exe);
- if (llvm::sys::fs::can_execute(FilePath.c_str()))
- return FilePath.str();
- }
-
- return Exe;
+ SmallString<128> FilePath(MSVC.getSubDirectoryPath(
+ toolchains::MSVCToolChain::SubDirectoryType::Bin));
+ llvm::sys::path::append(FilePath, Exe);
+ return llvm::sys::fs::can_execute(FilePath) ? FilePath.str() : Exe;
}
void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@@ -76,7 +298,8 @@
const ArgList &Args,
const char *LinkingOutput) const {
ArgStringList CmdArgs;
- const ToolChain &TC = getToolChain();
+
+ auto &TC = static_cast<const toolchains::MSVCToolChain &>(getToolChain());
assert((Output.isFilename() || Output.isNothing()) && "invalid output");
if (Output.isFilename())
@@ -92,37 +315,20 @@
// did not run vcvarsall), try to build a consistent link environment. If
// the environment variable is set however, assume the user knows what
// they're doing.
- std::string VisualStudioDir;
- const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);
- if (MSVC.getVisualStudioInstallDir(VisualStudioDir)) {
- SmallString<128> LibDir(VisualStudioDir);
- llvm::sys::path::append(LibDir, "VC", "lib");
- switch (MSVC.getArch()) {
- case llvm::Triple::x86:
- // x86 just puts the libraries directly in lib
- break;
- case llvm::Triple::x86_64:
- llvm::sys::path::append(LibDir, "amd64");
- break;
- case llvm::Triple::arm:
- llvm::sys::path::append(LibDir, "arm");
- break;
- default:
- break;
- }
- CmdArgs.push_back(
- Args.MakeArgString(std::string("-libpath:") + LibDir.c_str()));
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine("-libpath:") +
+ TC.getSubDirectoryPath(
+ toolchains::MSVCToolChain::SubDirectoryType::Lib)));
- if (MSVC.useUniversalCRT(VisualStudioDir)) {
- std::string UniversalCRTLibPath;
- if (MSVC.getUniversalCRTLibraryPath(UniversalCRTLibPath))
- CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") +
- UniversalCRTLibPath));
- }
+ if (TC.useUniversalCRT()) {
+ std::string UniversalCRTLibPath;
+ if (TC.getUniversalCRTLibraryPath(UniversalCRTLibPath))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath));
}
std::string WindowsSdkLibPath;
- if (MSVC.getWindowsSDKLibraryPath(WindowsSdkLibPath))
+ if (TC.getWindowsSDKLibraryPath(WindowsSdkLibPath))
CmdArgs.push_back(
Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
}
@@ -247,8 +453,7 @@
// If we're using the MSVC linker, it's not sufficient to just use link
// from the program PATH, because other environments like GnuWin32 install
// their own link.exe which may come first.
- linkPath = FindVisualStudioExecutable(TC, "link.exe",
- C.getDriver().getClangProgramPath());
+ linkPath = FindVisualStudioExecutable(TC, "link.exe");
} else {
linkPath = Linker;
llvm::sys::path::replace_extension(linkPath, "exe");
@@ -381,9 +586,7 @@
Args.MakeArgString(std::string("/Fo") + Output.getFilename());
CmdArgs.push_back(Fo);
- const Driver &D = getToolChain().getDriver();
- std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe",
- D.getClangProgramPath());
+ std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe");
return llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
CmdArgs, Inputs);
}
@@ -394,9 +597,19 @@
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
+
+ // Check the environment first, since that's probably the user telling us
+ // what they want to use.
+ // Failing that, just try to find the newest Visual Studio version we can
+ // and use its default VC toolchain.
+ findVCToolChainViaEnvironment(VCToolChainPath, IsVS2017OrNewer) ||
+ findVCToolChainViaSetupConfig(VCToolChainPath, IsVS2017OrNewer) ||
+ findVCToolChainViaRegistry(VCToolChainPath, IsVS2017OrNewer);
}
Tool *MSVCToolChain::buildLinker() const {
+ if (VCToolChainPath.empty())
+ getDriver().Diag(clang::diag::warn_drv_msvc_not_found);
return new tools::visualstudio::Linker(*this);
}
@@ -444,6 +657,72 @@
CudaInstallation.print(OS);
}
+// Windows SDKs and VC Toolchains group their contents into subdirectories based
+// on the target architecture. This function converts an llvm::Triple::ArchType
+// to the corresponding subdirectory name.
+static const char *llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch) {
+ using ArchType = llvm::Triple::ArchType;
+ switch (Arch) {
+ case ArchType::x86:
+ return "x86";
+ case ArchType::x86_64:
+ return "x64";
+ case ArchType::arm:
+ return "arm";
+ default:
+ return "";
+ }
+}
+
+// Similar to the above function, but for Visual Studios before VS2017.
+static const char *llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch) {
+ using ArchType = llvm::Triple::ArchType;
+ switch (Arch) {
+ case ArchType::x86:
+ // x86 is default in legacy VC toolchains.
+ // e.g. x86 libs are directly in /lib as opposed to /lib/x86.
+ return "";
+ case ArchType::x86_64:
+ return "amd64";
+ case ArchType::arm:
+ return "arm";
+ default:
+ return "";
+ }
+}
+
+// Get the path to a specific subdirectory in the current toolchain for
+// a given target architecture.
+// VS2017 changed the VC toolchain layout, so this should be used instead
+// of hardcoding paths.
+std::string
+MSVCToolChain::getSubDirectoryPath(SubDirectoryType Type,
+ llvm::Triple::ArchType TargetArch) const {
+ llvm::SmallString<256> Path(VCToolChainPath);
+ switch (Type) {
+ case SubDirectoryType::Bin:
+ if (IsVS2017OrNewer) {
+ bool HostIsX64 =
+ llvm::Triple(llvm::sys::getProcessTriple()).isArch64Bit();
+ llvm::sys::path::append(Path, "bin", (HostIsX64 ? "HostX64" : "HostX86"),
+ llvmArchToWindowsSDKArch(TargetArch));
+
+ } else {
+ llvm::sys::path::append(Path, "bin", llvmArchToLegacyVCArch(TargetArch));
+ }
+ break;
+ case SubDirectoryType::Include:
+ llvm::sys::path::append(Path, "include");
+ break;
+ case SubDirectoryType::Lib:
+ llvm::sys::path::append(
+ Path, "lib", IsVS2017OrNewer ? llvmArchToWindowsSDKArch(TargetArch)
+ : llvmArchToLegacyVCArch(TargetArch));
+ break;
+ }
+ return Path.str();
+}
+
#ifdef USE_WIN32
static bool readFullStringValue(HKEY hkey, const char *valueName,
std::string &value) {
@@ -573,27 +852,12 @@
#endif // USE_WIN32
}
-// Convert LLVM's ArchType
-// to the corresponding name of Windows SDK libraries subfolder
-static StringRef getWindowsSDKArch(llvm::Triple::ArchType Arch) {
- switch (Arch) {
- case llvm::Triple::x86:
- return "x86";
- case llvm::Triple::x86_64:
- return "x64";
- case llvm::Triple::arm:
- return "arm";
- default:
- return "";
- }
-}
-
// Find the most recent version of Universal CRT or Windows 10 SDK.
// vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include
// directory by name and uses the last one of the list.
// So we compare entry names lexicographically to find the greatest one.
-static bool getWindows10SDKVersion(const std::string &SDKPath,
- std::string &SDKVersion) {
+static bool getWindows10SDKVersionFromPath(const std::string &SDKPath,
+ std::string &SDKVersion) {
SDKVersion.clear();
std::error_code EC;
@@ -617,9 +881,9 @@
}
/// \brief Get Windows SDK installation directory.
-bool MSVCToolChain::getWindowsSDKDir(std::string &Path, int &Major,
- std::string &WindowsSDKIncludeVersion,
- std::string &WindowsSDKLibVersion) const {
+static bool getWindowsSDKDir(std::string &Path, int &Major,
+ std::string &WindowsSDKIncludeVersion,
+ std::string &WindowsSDKLibVersion) {
std::string RegistrySDKVersion;
// Try the Windows registry.
if (!getSystemRegistryString(
@@ -651,7 +915,7 @@
return !WindowsSDKLibVersion.empty();
}
if (Major == 10) {
- if (!getWindows10SDKVersion(Path, WindowsSDKIncludeVersion))
+ if (!getWindows10SDKVersionFromPath(Path, WindowsSDKIncludeVersion))
return false;
WindowsSDKLibVersion = WindowsSDKIncludeVersion;
return true;
@@ -674,7 +938,10 @@
llvm::SmallString<128> libPath(sdkPath);
llvm::sys::path::append(libPath, "Lib");
- if (sdkMajor <= 7) {
+ if (sdkMajor >= 8) {
+ llvm::sys::path::append(libPath, windowsSDKLibVersion, "um",
+ llvmArchToWindowsSDKArch(getArch()));
+ } else {
switch (getArch()) {
// In Windows SDK 7.x, x86 libraries are directly in the Lib folder.
case llvm::Triple::x86:
@@ -688,11 +955,6 @@
default:
return false;
}
- } else {
- const StringRef archName = getWindowsSDKArch(getArch());
- if (archName.empty())
- return false;
- llvm::sys::path::append(libPath, windowsSDKLibVersion, "um", archName);
}
path = libPath.str();
@@ -701,16 +963,14 @@
// Check if the Include path of a specified version of Visual Studio contains
// specific header files. If not, they are probably shipped with Universal CRT.
-bool clang::driver::toolchains::MSVCToolChain::useUniversalCRT(
- std::string &VisualStudioDir) const {
- llvm::SmallString<128> TestPath(VisualStudioDir);
- llvm::sys::path::append(TestPath, "VC\\include\\stdlib.h");
-
+bool MSVCToolChain::useUniversalCRT() const {
+ llvm::SmallString<128> TestPath(
+ getSubDirectoryPath(SubDirectoryType::Include));
+ llvm::sys::path::append(TestPath, "stdlib.h");
return !llvm::sys::fs::exists(TestPath);
}
-bool MSVCToolChain::getUniversalCRTSdkDir(std::string &Path,
- std::string &UCRTVersion) const {
+static bool getUniversalCRTSdkDir(std::string &Path, std::string &UCRTVersion) {
// vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry
// for the specific key "KitsRoot10". So do we.
if (!getSystemRegistryString(
@@ -718,7 +978,7 @@
Path, nullptr))
return false;
- return getWindows10SDKVersion(Path, UCRTVersion);
+ return getWindows10SDKVersionFromPath(Path, UCRTVersion);
}
bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const {
@@ -729,7 +989,7 @@
if (!getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion))
return false;
- StringRef ArchName = getWindowsSDKArch(getArch());
+ StringRef ArchName = llvmArchToWindowsSDKArch(getArch());
if (ArchName.empty())
return false;
@@ -740,104 +1000,18 @@
return true;
}
-// Get the location to use for Visual Studio binaries. The location priority
-// is: %VCINSTALLDIR% > %PATH% > newest copy of Visual Studio installed on
-// system (as reported by the registry).
-bool MSVCToolChain::getVisualStudioBinariesFolder(const char *clangProgramPath,
- std::string &path) const {
- path.clear();
-
- SmallString<128> BinDir;
-
- // First check the environment variables that vsvars32.bat sets.
- llvm::Optional<std::string> VcInstallDir =
- llvm::sys::Process::GetEnv("VCINSTALLDIR");
- if (VcInstallDir.hasValue()) {
- BinDir = VcInstallDir.getValue();
- llvm::sys::path::append(BinDir, "bin");
- } else {
- // Next walk the PATH, trying to find a cl.exe in the path. If we find one,
- // use that. However, make sure it's not clang's cl.exe.
- llvm::Optional<std::string> OptPath = llvm::sys::Process::GetEnv("PATH");
- if (OptPath.hasValue()) {
- const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'};
- SmallVector<StringRef, 8> PathSegments;
- llvm::SplitString(OptPath.getValue(), PathSegments, EnvPathSeparatorStr);
-
- for (StringRef PathSegment : PathSegments) {
- if (PathSegment.empty())
- continue;
-
- SmallString<128> FilePath(PathSegment);
- llvm::sys::path::append(FilePath, "cl.exe");
- // Checking if cl.exe exists is a small optimization over calling
- // can_execute, which really only checks for existence but will also do
- // extra checks for cl.exe.exe. These add up when walking a long path.
- if (llvm::sys::fs::exists(FilePath.c_str()) &&
- !llvm::sys::fs::equivalent(FilePath.c_str(), clangProgramPath)) {
- // If we found it on the PATH, use it exactly as is with no
- // modifications.
- path = PathSegment;
- return true;
- }
- }
- }
-
- std::string installDir;
- // With no VCINSTALLDIR and nothing on the PATH, if we can't find it in the
- // registry then we have no choice but to fail.
- if (!getVisualStudioInstallDir(installDir))
- return false;
-
- // Regardless of what binary we're ultimately trying to find, we make sure
- // that this is a Visual Studio directory by checking for cl.exe. We use
- // cl.exe instead of other binaries like link.exe because programs such as
- // GnuWin32 also have a utility called link.exe, so cl.exe is the least
- // ambiguous.
- BinDir = installDir;
- llvm::sys::path::append(BinDir, "VC", "bin");
- SmallString<128> ClPath(BinDir);
- llvm::sys::path::append(ClPath, "cl.exe");
-
- if (!llvm::sys::fs::can_execute(ClPath.c_str()))
- return false;
- }
-
- if (BinDir.empty())
- return false;
-
- switch (getArch()) {
- case llvm::Triple::x86:
- break;
- case llvm::Triple::x86_64:
- llvm::sys::path::append(BinDir, "amd64");
- break;
- case llvm::Triple::arm:
- llvm::sys::path::append(BinDir, "arm");
- break;
- default:
- // Whatever this is, Visual Studio doesn't have a toolchain for it.
- return false;
- }
- path = BinDir.str();
- return true;
-}
-
-VersionTuple MSVCToolChain::getMSVCVersionFromTriple() const {
+static VersionTuple getMSVCVersionFromTriple(const llvm::Triple &Triple) {
unsigned Major, Minor, Micro;
- getTriple().getEnvironmentVersion(Major, Minor, Micro);
+ Triple.getEnvironmentVersion(Major, Minor, Micro);
if (Major || Minor || Micro)
return VersionTuple(Major, Minor, Micro);
return VersionTuple();
}
-VersionTuple MSVCToolChain::getMSVCVersionFromExe() const {
+static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) {
VersionTuple Version;
#ifdef USE_WIN32
- std::string BinPath;
- if (!getVisualStudioBinariesFolder("", BinPath))
- return Version;
- SmallString<128> ClExe(BinPath);
+ SmallString<128> ClExe(BinDir);
llvm::sys::path::append(ClExe, "cl.exe");
std::wstring ClExeWide;
@@ -870,62 +1044,6 @@
return Version;
}
-// Get Visual Studio installation directory.
-bool MSVCToolChain::getVisualStudioInstallDir(std::string &path) const {
- // First check the environment variables that vsvars32.bat sets.
- if (llvm::Optional<std::string> VcInstallDir =
- llvm::sys::Process::GetEnv("VCINSTALLDIR")) {
- path = std::move(*VcInstallDir);
- path = path.substr(0, path.find("\\VC"));
- return true;
- }
-
- std::string vsIDEInstallDir;
- std::string vsExpressIDEInstallDir;
- // Then try the windows registry.
- bool hasVCDir =
- getSystemRegistryString("SOFTWARE\\Microsoft\\VisualStudio\\$VERSION",
- "InstallDir", vsIDEInstallDir, nullptr);
- if (hasVCDir && !vsIDEInstallDir.empty()) {
- path = vsIDEInstallDir.substr(0, vsIDEInstallDir.find("\\Common7\\IDE"));
- return true;
- }
-
- bool hasVCExpressDir =
- getSystemRegistryString("SOFTWARE\\Microsoft\\VCExpress\\$VERSION",
- "InstallDir", vsExpressIDEInstallDir, nullptr);
- if (hasVCExpressDir && !vsExpressIDEInstallDir.empty()) {
- path = vsExpressIDEInstallDir.substr(
- 0, vsIDEInstallDir.find("\\Common7\\IDE"));
- return true;
- }
-
- // Try the environment.
- std::string vcomntools;
- if (llvm::Optional<std::string> vs120comntools =
- llvm::sys::Process::GetEnv("VS120COMNTOOLS"))
- vcomntools = std::move(*vs120comntools);
- else if (llvm::Optional<std::string> vs100comntools =
- llvm::sys::Process::GetEnv("VS100COMNTOOLS"))
- vcomntools = std::move(*vs100comntools);
- else if (llvm::Optional<std::string> vs90comntools =
- llvm::sys::Process::GetEnv("VS90COMNTOOLS"))
- vcomntools = std::move(*vs90comntools);
- else if (llvm::Optional<std::string> vs80comntools =
- llvm::sys::Process::GetEnv("VS80COMNTOOLS"))
- vcomntools = std::move(*vs80comntools);
-
- // Find any version we can.
- if (!vcomntools.empty()) {
- size_t p = vcomntools.find("\\Common7\\Tools");
- if (p != std::string::npos)
- vcomntools.resize(p);
- path = std::move(vcomntools);
- return true;
- }
- return false;
-}
-
void MSVCToolChain::AddSystemIncludeWithSubfolder(
const ArgList &DriverArgs, ArgStringList &CC1Args,
const std::string &folder, const Twine &subfolder1, const Twine &subfolder2,
@@ -964,14 +1082,13 @@
return;
}
- std::string VSDir;
-
// When built with access to the proper Windows APIs, try to actually find
// the correct include paths first.
- if (getVisualStudioInstallDir(VSDir)) {
- AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, VSDir, "VC\\include");
+ if (!VCToolChainPath.empty()) {
+ addSystemInclude(DriverArgs, CC1Args,
+ getSubDirectoryPath(SubDirectoryType::Include));
- if (useUniversalCRT(VSDir)) {
+ if (useUniversalCRT()) {
std::string UniversalCRTSdkPath;
std::string UCRTVersion;
if (getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) {
@@ -1002,9 +1119,8 @@
AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
"include");
}
- } else {
- addSystemInclude(DriverArgs, CC1Args, VSDir);
}
+
return;
}
@@ -1031,8 +1147,10 @@
const ArgList &Args) const {
bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment();
VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args);
- if (MSVT.empty()) MSVT = getMSVCVersionFromTriple();
- if (MSVT.empty() && IsWindowsMSVC) MSVT = getMSVCVersionFromExe();
+ if (MSVT.empty())
+ MSVT = getMSVCVersionFromTriple(getTriple());
+ if (MSVT.empty() && IsWindowsMSVC)
+ MSVT = getMSVCVersionFromExe(getSubDirectoryPath(SubDirectoryType::Bin));
if (MSVT.empty() &&
Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
IsWindowsMSVC)) {