Index: include/clang/Basic/DiagnosticDriverKinds.td =================================================================== --- include/clang/Basic/DiagnosticDriverKinds.td +++ include/clang/Basic/DiagnosticDriverKinds.td @@ -277,4 +277,8 @@ 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 re-running Clang from a devleoper command prompt">; } Index: lib/Driver/MSVCToolChain.cpp =================================================================== --- lib/Driver/MSVCToolChain.cpp +++ lib/Driver/MSVCToolChain.cpp @@ -23,16 +23,20 @@ #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 -// Include the necessary headers to interface with the Windows registry and -// environment. #if defined(LLVM_ON_WIN32) -#define USE_WIN32 + #define USE_WIN32 + #if 0 + #define USE_VS_SETUP_CONFIG + #endif #endif +// Include the necessary headers to interface with the Windows registry and +// environment. #ifdef USE_WIN32 #define WIN32_LEAN_AND_MEAN #define NOGDI @@ -42,20 +46,261 @@ #include #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 + #include + #include + _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; -MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple, +// 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); + +// Attempts to find the "best" usable VC toolchain. +static bool findVCToolChainPath(std::string &Path, bool &IsVS2017OrNewer) { + // Check the environment first, since that's probably the user telling us + // what they want to use. These variables are typically set by vcvarsall.bat + // when launching a developer command prompt. + if (llvm::Optional 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 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 we find. + if (llvm::Optional PathEnv = + llvm::sys::Process::GetEnv("PATH")) { + const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'}; + llvm::SmallVector PathSegments; + llvm::SplitString(PathEnv.getValue(), PathSegments, EnvPathSeparatorStr); + + for (StringRef PathSegment : PathSegments) { + if (PathSegment.empty()) + continue; + + // If cl.exe doesn't exist, then this definitely isn't a VC toolchain. + llvm::SmallString<128> PotentialClPath(PathSegment); + llvm::sys::path::append(PotentialClPath, "cl.exe"); + if (!llvm::sys::fs::exists(PotentialClPath)) + 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. + llvm::SmallString<128> PotentialLinkPath(PathSegment); + llvm::sys::path::append(PotentialLinkPath, "link.exe"); + if (!llvm::sys::fs::exists(PotentialLinkPath)) + continue; + + // whatever/VC/bin --> old toolchain, VC dir is toolchain dir. + if (llvm::sys::path::filename(PathSegment) == "bin") { + llvm::StringRef ParentPath = llvm::sys::path::parent_path(PathSegment); + 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::SmallVector ExpectedPrefixes = + {"", "Host", "bin", "", "MSVC", "Tools", "VC"}; + + llvm::sys::path::reverse_iterator + It = llvm::sys::path::rbegin(PathSegment), + End = llvm::sys::path::rend(PathSegment); + 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(PathSegment); + for (int i = 0; i < 3; ++i) + ToolChainPath = llvm::sys::path::parent_path(ToolChainPath); + + Path = ToolChainPath; + IsVS2017OrNewer = true; + return true; + } + + NotAToolChain: + ; + } + } + + // We reach this point if the environment doesn't lead to a toolchain, + // and so we probably aren't being run from a developer command prompt. + // The plan from now is to find the newest Visual Studio version we can, and + // use its default VC toolchain.. + // TODO: Perhaps have an option to let the user select the toolchain that + // they want to use? + +#ifdef USE_VS_SETUP_CONFIG + // Query the Setup Config server for installs. + // This is the preferred way to discover new Visual Studios, as they're no + // longer listed in the registry. + // An explicit scope is established to ensure the COM pointers get released + // as soon as we're done with them. + { + 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 unique_ptr will put the regular error handler back when we leave + // this scope. + _set_com_error_handler([](HRESULT, IErrorInfo *) { }); + std::unique_ptr + ComErrorHandlerPtr(&_com_raise_error, &_set_com_error_handler); + + ISetupConfigurationPtr Query; + HR = Query.CreateInstance(__uuidof(SetupConfiguration)); + if (FAILED(HR)) goto ConfigQueryUnsuccessful; + + IEnumSetupInstancesPtr EnumInstances; + HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances); + if (FAILED(HR)) goto ConfigQueryUnsuccessful; + + ISetupInstancePtr Instance; + HR = EnumInstances->Next(1, &Instance, nullptr); + if (HR != S_OK) goto ConfigQueryUnsuccessful; + + ISetupInstancePtr NewestInstance(Instance); + uint64_t NewestVersionNum; + { + bstr_t VersionString; + HR = NewestInstance->GetInstallationVersion(VersionString.GetAddress()); + if (FAILED(HR)) goto ConfigQueryUnsuccessful; + HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, + &NewestVersionNum); + if (FAILED(HR)) goto ConfigQueryUnsuccessful; + } + + 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)) goto ConfigQueryUnsuccessful; + + 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) + goto ConfigQueryUnsuccessful; + + llvm::SmallString<256> ToolchainPath(VCRootPath); + llvm::sys::path::append(ToolchainPath, + "Tools", + "MSVC", + ToolsVersionFile->get()->getBuffer().rtrim()); + if (!llvm::sys::fs::is_directory(ToolchainPath)) + goto ConfigQueryUnsuccessful; + + Path = ToolchainPath.str(); + IsVS2017OrNewer = true; + return true; + } + +ConfigQueryUnsuccessful: + ; +#endif /*USE_VS_SETUP_CONFIG*/ + + // If the environment checks and Setup Config queries are unsuccessful, + // our last hope is that we can find an install in the registry. + // VS2017 and newer don't get added to the registry. So if we find something + // here, we know that it's an older version. + 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, 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); + findVCToolChainPath(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); } @@ -103,6 +348,73 @@ 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 *llvmArchToSubDirectoryName(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 ""; + } +} + +// Get the path to a specific subdirectory in the current toolchain. +// VS2017 changed the VC toolchain layout, so this should be used instead +// of hardcoding paths. +std::string MSVCToolChain::getSubDirectoryPath(SubDirectoryType Type) const { + auto llvmArchToLegacyVCSubDirectoryName = + [](llvm::Triple::ArchType Arch) -> const char * { + 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 ""; + } + }; + + 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"), + llvmArchToSubDirectoryName(getArch())); + } else { + llvm::sys::path::append(Path, + "bin", + llvmArchToLegacyVCSubDirectoryName(getArch())); + } + break; + case SubDirectoryType::Include: + llvm::sys::path::append(Path, "include"); + break; + case SubDirectoryType::Lib: + llvm::sys::path::append(Path, + "lib", + IsVS2017OrNewer + ? llvmArchToSubDirectoryName(getArch()) + : llvmArchToLegacyVCSubDirectoryName(getArch())); + break; + } + return Path.str(); +} + #ifdef USE_WIN32 static bool readFullStringValue(HKEY hkey, const char *valueName, std::string &value) { @@ -232,27 +544,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; @@ -276,9 +573,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( @@ -310,7 +607,7 @@ return !WindowsSDKLibVersion.empty(); } if (Major == 10) { - if (!getWindows10SDKVersion(Path, WindowsSDKIncludeVersion)) + if (!getWindows10SDKVersionFromPath(Path, WindowsSDKIncludeVersion)) return false; WindowsSDKLibVersion = WindowsSDKIncludeVersion; return true; @@ -333,9 +630,14 @@ llvm::SmallString<128> libPath(sdkPath); llvm::sys::path::append(libPath, "Lib"); - if (sdkMajor <= 7) { + if (sdkMajor >= 8) { + llvm::sys::path::append(libPath, + windowsSDKLibVersion, + "um", + llvmArchToSubDirectoryName(getArch())); + } else { 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: @@ -347,11 +649,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(); @@ -360,24 +657,22 @@ // 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( - "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10", - Path, nullptr)) + "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", + "KitsRoot10", Path, nullptr)) return false; - return getWindows10SDKVersion(Path, UCRTVersion); + return getWindows10SDKVersionFromPath(Path, UCRTVersion); } bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const { @@ -388,7 +683,7 @@ if (!getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) return false; - StringRef ArchName = getWindowsSDKArch(getArch()); + StringRef ArchName = llvmArchToSubDirectoryName(getArch()); if (ArchName.empty()) return false; @@ -399,89 +694,6 @@ 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 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 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"); - // 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; getTriple().getEnvironmentVersion(Major, Minor, Micro); @@ -493,10 +705,7 @@ VersionTuple MSVCToolChain::getMSVCVersionFromExe() const { VersionTuple Version; #ifdef USE_WIN32 - std::string BinPath; - if (!getVisualStudioBinariesFolder("", BinPath)) - return Version; - SmallString<128> ClExe(BinPath); + SmallString<128> ClExe(getSubDirectoryPath(SubDirectoryType::Bin)); llvm::sys::path::append(ClExe, "cl.exe"); std::wstring ClExeWide; @@ -529,62 +738,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 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 vs120comntools = - llvm::sys::Process::GetEnv("VS120COMNTOOLS")) - vcomntools = std::move(*vs120comntools); - else if (llvm::Optional vs100comntools = - llvm::sys::Process::GetEnv("VS100COMNTOOLS")) - vcomntools = std::move(*vs100comntools); - else if (llvm::Optional vs90comntools = - llvm::sys::Process::GetEnv("VS90COMNTOOLS")) - vcomntools = std::move(*vs90comntools); - else if (llvm::Optional 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, @@ -623,14 +776,14 @@ 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)) { @@ -661,9 +814,8 @@ AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, "include"); } - } else { - addSystemInclude(DriverArgs, CC1Args, VSDir); } + return; } Index: lib/Driver/ToolChains.h =================================================================== --- lib/Driver/ToolChains.h +++ lib/Driver/ToolChains.h @@ -1155,6 +1155,13 @@ bool isPIEDefault() const override; bool isPICDefaultForced() const override; + enum class SubDirectoryType { + Bin, + Include, + Lib, + }; + std::string getSubDirectoryPath(SubDirectoryType Type) const; + void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; @@ -1163,19 +1170,12 @@ llvm::opt::ArgStringList &CC1Args) const override; void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + 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(std::string &visualStudioDir) const; - bool getUniversalCRTSdkDir(std::string &path, std::string &ucrtVersion) const; + bool useUniversalCRT() 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; @@ -1196,7 +1196,11 @@ Tool *buildLinker() const override; Tool *buildAssembler() const override; + private: + std::string VCToolChainPath; + bool IsVS2017OrNewer; + VersionTuple getMSVCVersionFromTriple() const; VersionTuple getMSVCVersionFromExe() const; Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -10809,16 +10809,10 @@ const char *Exe, const char *ClangProgramPath) { const auto &MSVC = static_cast(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, @@ -10843,33 +10837,17 @@ // 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(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( + std::string("-libpath:") + + MSVC.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 (MSVC.useUniversalCRT()) { + std::string UniversalCRTLibPath; + if (MSVC.getUniversalCRTLibraryPath(UniversalCRTLibPath)) + CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + + UniversalCRTLibPath)); } std::string WindowsSdkLibPath;