Index: lib/Driver/ToolChains.h =================================================================== --- lib/Driver/ToolChains.h +++ lib/Driver/ToolChains.h @@ -746,7 +746,9 @@ llvm::opt::ArgStringList &CC1Args) const override; bool getWindowsSDKDir(std::string &path, int &major, int &minor) const; - bool getVisualStudioDir(std::string &path) const; + bool getVisualStudioInstallDir(std::string &path) const; + bool getVisualStudioBinariesFolder(const char *clangProgramPath, + std::string &path) const; protected: void AddSystemIncludeWithSubfolder(const llvm::opt::ArgList &DriverArgs, Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -7816,37 +7816,12 @@ static std::string FindVisualStudioExecutable(const ToolChain &TC, const char *Exe, const char *ClangProgramPath) { - // Since a particular Visual Studio executable is tied to a set of system - // includes and libraries, first try to use the same location that we use for - // the include paths to ensure that a consistent build environment is located. const toolchains::Windows &WTC = static_cast(TC); - std::string visualStudioDir; - if (WTC.getVisualStudioDir(visualStudioDir)) { - SmallString<128> VSDir(visualStudioDir); - llvm::sys::path::append(VSDir, "VC\\bin"); - llvm::sys::path::append(VSDir, Exe); - if (llvm::sys::fs::can_execute(VSDir.c_str())) - return VSDir.str(); - } - - // If it could not be found, we're already probably broken, but try to - // fallback to PATH anyway. - llvm::Optional OptPath = llvm::sys::Process::GetEnv("PATH"); - if (!OptPath.hasValue()) - return Exe; - - const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'}; - SmallVector PathSegments; - llvm::SplitString(OptPath.getValue(), PathSegments, EnvPathSeparatorStr); - - for (StringRef PathSegment : PathSegments) { - if (PathSegment.empty()) - continue; - - SmallString<128> FilePath(PathSegment); + std::string visualStudioBinDir; + if (WTC.getVisualStudioBinariesFolder(ClangProgramPath, visualStudioBinDir)) { + SmallString<128> FilePath(visualStudioBinDir); llvm::sys::path::append(FilePath, Exe); - if (llvm::sys::fs::can_execute(FilePath.c_str()) && - !llvm::sys::fs::equivalent(FilePath.c_str(), ClangProgramPath)) + if (llvm::sys::fs::can_execute(FilePath.c_str())) return FilePath.str(); } Index: lib/Driver/WindowsToolChain.cpp =================================================================== --- lib/Driver/WindowsToolChain.cpp +++ lib/Driver/WindowsToolChain.cpp @@ -14,10 +14,13 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Config/llvm-config.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Process.h" // Include the necessary headers to interface with the Windows registry and // environment. @@ -211,8 +214,87 @@ return hasSDKDir && !path.empty(); } +// 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 Windows::getVisualStudioBinariesFolder(const char *clangProgramPath, + std::string &path) const { + path.clear(); + + SmallString<128> BinDir; + + // First check the environment variables that vsvars32.bat sets. + const char *vcinstalldir = getenv("VCINSTALLDIR"); + if (vcinstalldir) { + BinDir = vcinstalldir; + llvm::sys::path::append(BinDir, "VC"); + } 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 OptPath = llvm::sys::Process::GetEnv("PATH"); + if (OptPath.hasValue()) { + const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'}; + SmallVector 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"); + if (llvm::sys::fs::can_execute(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; +} + // Get Visual Studio installation directory. -bool Windows::getVisualStudioDir(std::string &path) const { +bool Windows::getVisualStudioInstallDir(std::string &path) const { // First check the environment variables that vsvars32.bat sets. const char *vcinstalldir = getenv("VCINSTALLDIR"); if (vcinstalldir) { @@ -305,7 +387,7 @@ // When built with access to the proper Windows APIs, try to actually find // the correct include paths first. - if (getVisualStudioDir(VSDir)) { + if (getVisualStudioInstallDir(VSDir)) { AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, VSDir, "VC\\include"); std::string WindowsSDKDir;