r293924 - Revert "[Driver] Updated for Visual Studio 2017"

Reid Kleckner via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 2 11:36:22 PST 2017


Author: rnk
Date: Thu Feb  2 13:36:22 2017
New Revision: 293924

URL: http://llvm.org/viewvc/llvm-project?rev=293924&view=rev
Log:
Revert "[Driver] Updated for Visual Studio 2017"

This reverts commit r293923. It causes test failures on Linux that need
time to debug.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td
    cfe/trunk/lib/Driver/MSVCToolChain.cpp
    cfe/trunk/lib/Driver/ToolChains.h
    cfe/trunk/lib/Driver/Tools.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td?rev=293924&r1=293923&r2=293924&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td Thu Feb  2 13:36:22 2017
@@ -281,8 +281,4 @@ def warn_drv_ps4_sdk_dir : Warning<
 def err_drv_unsupported_linker : Error<"unsupported value '%0' for -linker option">;
 def err_drv_defsym_invalid_format : Error<"defsym must be of the form: sym=value: %0">;
 def err_drv_defsym_invalid_symval : Error<"Value is not an integer: %0">;
-
-def err_drv_msvc_not_found : Error<
-  "unable to find a Visual Studio installation; "
-  "try running Clang from a developer command prompt">;
 }

Modified: cfe/trunk/lib/Driver/MSVCToolChain.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/MSVCToolChain.cpp?rev=293924&r1=293923&r2=293924&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/MSVCToolChain.cpp (original)
+++ cfe/trunk/lib/Driver/MSVCToolChain.cpp Thu Feb  2 13:36:22 2017
@@ -23,23 +23,16 @@
 #include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Host.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Process.h"
 #include <cstdio>
 
+// Include the necessary headers to interface with the Windows registry and
+// environment.
 #if defined(LLVM_ON_WIN32)
-  #define USE_WIN32
-
-  // FIXME: Make this configurable with cmake when the final version of the API
-  //        has been released.
-  #if 0
-    #define USE_VS_SETUP_CONFIG
-  #endif
+#define USE_WIN32
 #endif
 
-// Include the necessary headers to interface with the Windows registry and
-// environment.
 #ifdef USE_WIN32
   #define WIN32_LEAN_AND_MEAN
   #define NOGDI
@@ -49,265 +42,20 @@
   #include <windows.h>
 #endif
 
-// Include the headers needed for the setup config COM stuff and define
-// smart pointers for the interfaces we need.
-#ifdef USE_VS_SETUP_CONFIG
-  #include "clang/Basic/VirtualFileSystem.h"
-  #include "llvm/Support/COM.h"
-  #include <comdef.h>
-  #include <Setup.Configuration.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;
 using namespace clang::driver::toolchains;
 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" };
-
-        llvm::sys::path::reverse_iterator
-            It = llvm::sys::path::rbegin(PathEntry),
-            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) {
-#ifndef USE_VS_SETUP_CONFIG
-  return false;
-#else
-  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 {
-    SuppressCOMErrorsRAII() {
-      _set_com_error_handler([](HRESULT, IErrorInfo *) { });
-    }
-    ~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(Instance);
-  uint64_t NewestVersionNum;
-  {
-    bstr_t VersionString;
-    HR = NewestInstance->GetInstallationVersion(VersionString.GetAddress());
-    if (FAILED(HR)) return false;
-    HR = ISetupHelperPtr(Query)->ParseVersion(VersionString,
-                                              &NewestVersionNum);
-    if (FAILED(HR)) return false;
-  }
-
-  while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK) {
-    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 (VersionNum > NewestVersionNum) {
-      NewestInstance = Instance;
-      NewestVersionNum = VersionNum;
-    }
-  }
-
-  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 =
-      clang::vfs::getRealFileSystem()->getBufferForFile(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 /*USE_VS_SETUP_CONFIG*/
-}
-
-// 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;
-}
-
-MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple& Triple,
+MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
                              const ArgList &Args)
     : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) {
   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::err_drv_msvc_not_found);
-    return nullptr;
-  }
   return new tools::visualstudio::Linker(*this);
 }
 
@@ -355,77 +103,6 @@ void MSVCToolChain::printVerboseInfo(raw
   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) {
@@ -555,12 +232,27 @@ static bool getSystemRegistryString(cons
 #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 getWindows10SDKVersionFromPath(const std::string &SDKPath,
-                                           std::string &SDKVersion) {
+static bool getWindows10SDKVersion(const std::string &SDKPath,
+                                   std::string &SDKVersion) {
   SDKVersion.clear();
 
   std::error_code EC;
@@ -584,9 +276,9 @@ static bool getWindows10SDKVersionFromPa
 }
 
 /// \brief Get Windows SDK installation directory.
-static bool getWindowsSDKDir(std::string &Path, int &Major,
-                             std::string &WindowsSDKIncludeVersion,
-                             std::string &WindowsSDKLibVersion) {
+bool MSVCToolChain::getWindowsSDKDir(std::string &Path, int &Major,
+                                     std::string &WindowsSDKIncludeVersion,
+                                     std::string &WindowsSDKLibVersion) const {
   std::string RegistrySDKVersion;
   // Try the Windows registry.
   if (!getSystemRegistryString(
@@ -618,7 +310,7 @@ static bool getWindowsSDKDir(std::string
     return !WindowsSDKLibVersion.empty();
   }
   if (Major == 10) {
-    if (!getWindows10SDKVersionFromPath(Path, WindowsSDKIncludeVersion))
+    if (!getWindows10SDKVersion(Path, WindowsSDKIncludeVersion))
       return false;
     WindowsSDKLibVersion = WindowsSDKIncludeVersion;
     return true;
@@ -641,14 +333,9 @@ bool MSVCToolChain::getWindowsSDKLibrary
 
   llvm::SmallString<128> libPath(sdkPath);
   llvm::sys::path::append(libPath, "Lib");
-  if (sdkMajor >= 8) {
-    llvm::sys::path::append(libPath,
-      windowsSDKLibVersion,
-      "um",
-      llvmArchToWindowsSDKArch(getArch()));
-  } else {
+  if (sdkMajor <= 7) {
     switch (getArch()) {
-      // In Windows SDK 7.x, x86 libraries are directly in the Lib folder.
+    // In Windows SDK 7.x, x86 libraries are directly in the Lib folder.
     case llvm::Triple::x86:
       break;
     case llvm::Triple::x86_64:
@@ -660,6 +347,11 @@ bool MSVCToolChain::getWindowsSDKLibrary
     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();
@@ -668,22 +360,24 @@ bool MSVCToolChain::getWindowsSDKLibrary
 
 // 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 MSVCToolChain::useUniversalCRT() const {
-  llvm::SmallString<128> TestPath(getSubDirectoryPath(SubDirectoryType::Include));
-  llvm::sys::path::append(TestPath, "stdlib.h");
+bool clang::driver::toolchains::MSVCToolChain::useUniversalCRT(
+    std::string &VisualStudioDir) const {
+  llvm::SmallString<128> TestPath(VisualStudioDir);
+  llvm::sys::path::append(TestPath, "VC\\include\\stdlib.h");
+
   return !llvm::sys::fs::exists(TestPath);
 }
 
-static bool getUniversalCRTSdkDir(std::string &Path,
-                                  std::string &UCRTVersion) {
+bool MSVCToolChain::getUniversalCRTSdkDir(std::string &Path,
+                                          std::string &UCRTVersion) const {
   // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry
   // for the specific key "KitsRoot10". So do we.
   if (!getSystemRegistryString(
-          "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots",
-          "KitsRoot10", Path, nullptr))
+          "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10",
+          Path, nullptr))
     return false;
 
-  return getWindows10SDKVersionFromPath(Path, UCRTVersion);
+  return getWindows10SDKVersion(Path, UCRTVersion);
 }
 
 bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const {
@@ -694,7 +388,7 @@ bool MSVCToolChain::getUniversalCRTLibra
   if (!getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion))
     return false;
 
-  StringRef ArchName = llvmArchToWindowsSDKArch(getArch());
+  StringRef ArchName = getWindowsSDKArch(getArch());
   if (ArchName.empty())
     return false;
 
@@ -705,18 +399,104 @@ bool MSVCToolChain::getUniversalCRTLibra
   return true;
 }
 
-static VersionTuple getMSVCVersionFromTriple(const llvm::Triple &Triple) {
+// 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 {
   unsigned Major, Minor, Micro;
-  Triple.getEnvironmentVersion(Major, Minor, Micro);
+  getTriple().getEnvironmentVersion(Major, Minor, Micro);
   if (Major || Minor || Micro)
     return VersionTuple(Major, Minor, Micro);
   return VersionTuple();
 }
 
-static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) {
+VersionTuple MSVCToolChain::getMSVCVersionFromExe() const {
   VersionTuple Version;
 #ifdef USE_WIN32
-  SmallString<128> ClExe(BinDir);
+  std::string BinPath;
+  if (!getVisualStudioBinariesFolder("", BinPath))
+    return Version;
+  SmallString<128> ClExe(BinPath);
   llvm::sys::path::append(ClExe, "cl.exe");
 
   std::wstring ClExeWide;
@@ -749,6 +529,62 @@ static VersionTuple getMSVCVersionFromEx
   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,
@@ -787,14 +623,14 @@ void MSVCToolChain::AddClangSystemInclud
       return;
   }
 
+  std::string VSDir;
+
   // When built with access to the proper Windows APIs, try to actually find
   // the correct include paths first.
-  if (!VCToolChainPath.empty()) {
-    addSystemInclude(DriverArgs,
-                     CC1Args,
-                     getSubDirectoryPath(SubDirectoryType::Include));
+  if (getVisualStudioInstallDir(VSDir)) {
+    AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, VSDir, "VC\\include");
 
-    if (useUniversalCRT()) {
+    if (useUniversalCRT(VSDir)) {
       std::string UniversalCRTSdkPath;
       std::string UCRTVersion;
       if (getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) {
@@ -825,8 +661,9 @@ void MSVCToolChain::AddClangSystemInclud
         AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
                                       "include");
       }
+    } else {
+      addSystemInclude(DriverArgs, CC1Args, VSDir);
     }
-
     return;
   }
 
@@ -853,10 +690,8 @@ VersionTuple MSVCToolChain::computeMSVCV
                                                const ArgList &Args) const {
   bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment();
   VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args);
-  if (MSVT.empty())
-    MSVT = getMSVCVersionFromTriple(getTriple());
-  if (MSVT.empty() && IsWindowsMSVC)
-    MSVT = getMSVCVersionFromExe(getSubDirectoryPath(SubDirectoryType::Bin));
+  if (MSVT.empty()) MSVT = getMSVCVersionFromTriple();
+  if (MSVT.empty() && IsWindowsMSVC) MSVT = getMSVCVersionFromExe();
   if (MSVT.empty() &&
       Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
                    IsWindowsMSVC)) {

Modified: cfe/trunk/lib/Driver/ToolChains.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/ToolChains.h?rev=293924&r1=293923&r2=293924&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/ToolChains.h (original)
+++ cfe/trunk/lib/Driver/ToolChains.h Thu Feb  2 13:36:22 2017
@@ -1141,11 +1141,6 @@ public:
 };
 
 class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain {
-  std::string VCToolChainPath;
-  bool IsVS2017OrNewer;
-
-  CudaInstallationDetector CudaInstallation;
-
 public:
   MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
                 const llvm::opt::ArgList &Args);
@@ -1160,22 +1155,6 @@ public:
   bool isPIEDefault() const override;
   bool isPICDefaultForced() const override;
 
-  enum class SubDirectoryType {
-    Bin,
-    Include,
-    Lib,
-  };
-  std::string getSubDirectoryPath(SubDirectoryType Type,
-                                  llvm::Triple::ArchType TargetArch) const;
-
-  // Convenience overload.
-  // Uses the current target arch.
-  std::string getSubDirectoryPath(SubDirectoryType Type) const {
-    return getSubDirectoryPath(Type, getArch());
-  }
-
-  bool getIsVS2017OrNewer() const { return IsVS2017OrNewer; }
-
   void
   AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
                             llvm::opt::ArgStringList &CC1Args) const override;
@@ -1186,10 +1165,17 @@ public:
   void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
                           llvm::opt::ArgStringList &CC1Args) const override;
 
+  bool getWindowsSDKDir(std::string &path, int &major,
+                        std::string &windowsSDKIncludeVersion,
+                        std::string &windowsSDKLibVersion) const;
   bool getWindowsSDKLibraryPath(std::string &path) const;
   /// \brief Check if Universal CRT should be used if available
-  bool useUniversalCRT() const;
+  bool useUniversalCRT(std::string &visualStudioDir) const;
+  bool getUniversalCRTSdkDir(std::string &path, std::string &ucrtVersion) const;
   bool getUniversalCRTLibraryPath(std::string &path) const;
+  bool getVisualStudioInstallDir(std::string &path) const;
+  bool getVisualStudioBinariesFolder(const char *clangProgramPath,
+                                     std::string &path) const;
   VersionTuple
   computeMSVCVersion(const Driver *D,
                      const llvm::opt::ArgList &Args) const override;
@@ -1210,6 +1196,11 @@ protected:
 
   Tool *buildLinker() const override;
   Tool *buildAssembler() const override;
+private:
+  VersionTuple getMSVCVersionFromTriple() const;
+  VersionTuple getMSVCVersionFromExe() const;
+
+  CudaInstallationDetector CudaInstallation;
 };
 
 class LLVM_LIBRARY_VISIBILITY CrossWindowsToolChain : public Generic_GCC {

Modified: cfe/trunk/lib/Driver/Tools.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=293924&r1=293923&r2=293924&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Tools.cpp (original)
+++ cfe/trunk/lib/Driver/Tools.cpp Thu Feb  2 13:36:22 2017
@@ -10888,12 +10888,19 @@ void dragonfly::Linker::ConstructJob(Com
 // 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 *Exe,
+                                              const char *ClangProgramPath) {
   const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);
-  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);
+  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;
 }
 
 void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@@ -10902,7 +10909,7 @@ void visualstudio::Linker::ConstructJob(
                                         const ArgList &Args,
                                         const char *LinkingOutput) const {
   ArgStringList CmdArgs;
-  auto &TC = static_cast<const toolchains::MSVCToolChain &>(getToolChain());
+  const ToolChain &TC = getToolChain();
 
   assert((Output.isFilename() || Output.isNothing()) && "invalid output");
   if (Output.isFilename())
@@ -10918,20 +10925,37 @@ void visualstudio::Linker::ConstructJob(
     // 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.
-    CmdArgs.push_back(Args.MakeArgString(
-                          std::string("-libpath:")
-                          + TC.getSubDirectoryPath(toolchains::MSVCToolChain
-                                                   ::SubDirectoryType::Lib)));
-
-    if (TC.useUniversalCRT()) {
-      std::string UniversalCRTLibPath;
-      if (TC.getUniversalCRTLibraryPath(UniversalCRTLibPath))
-        CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:")
-                                             + UniversalCRTLibPath));
+    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()));
+
+      if (MSVC.useUniversalCRT(VisualStudioDir)) {
+        std::string UniversalCRTLibPath;
+        if (MSVC.getUniversalCRTLibraryPath(UniversalCRTLibPath))
+          CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") +
+                                               UniversalCRTLibPath));
+      }
     }
 
     std::string WindowsSdkLibPath;
-    if (TC.getWindowsSDKLibraryPath(WindowsSdkLibPath))
+    if (MSVC.getWindowsSDKLibraryPath(WindowsSdkLibPath))
       CmdArgs.push_back(
           Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
   }
@@ -11055,7 +11079,8 @@ void visualstudio::Linker::ConstructJob(
     // 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");
+    linkPath = FindVisualStudioExecutable(TC, "link.exe",
+                                          C.getDriver().getClangProgramPath());
   } else {
     linkPath = Linker;
     llvm::sys::path::replace_extension(linkPath, "exe");
@@ -11188,7 +11213,9 @@ std::unique_ptr<Command> visualstudio::C
       Args.MakeArgString(std::string("/Fo") + Output.getFilename());
   CmdArgs.push_back(Fo);
 
-  std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe");
+  const Driver &D = getToolChain().getDriver();
+  std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe",
+                                                D.getClangProgramPath());
   return llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
                                     CmdArgs, Inputs);
 }




More information about the cfe-commits mailing list