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
This commit is contained in:
Zachary Turner 2017-03-15 16:07:35 +00:00
parent 20055d4cd2
commit f630252349
5 changed files with 892 additions and 249 deletions

View File

@ -283,4 +283,8 @@ 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 warn_drv_msvc_not_found : Warning<
"unable to find a Visual Studio installation; "
"try running Clang from a developer command prompt">,
InGroup<InvalidOrNonExistentDirectory>;
}

View File

@ -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::driver::tools;
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 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
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 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// 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 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// 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 @@ std::unique_ptr<Command> visualstudio::Compiler::GetCommand(
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 @@ MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
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 @@ void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const {
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 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName,
#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 @@ static bool getWindows10SDKVersion(const std::string &SDKPath,
}
/// \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 @@ bool MSVCToolChain::getWindowsSDKDir(std::string &Path, int &Major,
return !WindowsSDKLibVersion.empty();
}
if (Major == 10) {
if (!getWindows10SDKVersion(Path, WindowsSDKIncludeVersion))
if (!getWindows10SDKVersionFromPath(Path, WindowsSDKIncludeVersion))
return false;
WindowsSDKLibVersion = WindowsSDKIncludeVersion;
return true;
@ -674,7 +938,10 @@ bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const {
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 @@ bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const {
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 @@ bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const {
// 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 @@ bool MSVCToolChain::getUniversalCRTSdkDir(std::string &Path,
Path, nullptr))
return false;
return getWindows10SDKVersion(Path, UCRTVersion);
return getWindows10SDKVersionFromPath(Path, UCRTVersion);
}
bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const {
@ -729,7 +989,7 @@ bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const {
if (!getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion))
return false;
StringRef ArchName = getWindowsSDKArch(getArch());
StringRef ArchName = llvmArchToWindowsSDKArch(getArch());
if (ArchName.empty())
return false;
@ -740,104 +1000,18 @@ bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const {
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 @@ VersionTuple MSVCToolChain::getMSVCVersionFromExe() const {
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 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
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 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
"include");
}
} else {
addSystemInclude(DriverArgs, CC1Args, VSDir);
}
return;
}
@ -1031,8 +1147,10 @@ VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D,
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)) {

View File

@ -78,6 +78,22 @@ 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;
@ -88,17 +104,10 @@ 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(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;
bool useUniversalCRT() const;
VersionTuple
computeMSVCVersion(const Driver *D,
const llvm::opt::ArgList &Args) const override;
@ -120,9 +129,8 @@ protected:
Tool *buildLinker() const override;
Tool *buildAssembler() const override;
private:
VersionTuple getMSVCVersionFromTriple() const;
VersionTuple getMSVCVersionFromExe() const;
std::string VCToolChainPath;
bool IsVS2017OrNewer;
CudaInstallationDetector CudaInstallation;
};

View File

@ -0,0 +1,514 @@
// <copyright file="Program.cpp" company="Microsoft Corporation">
// Copyright (C) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
// </copyright>
// <license>
// The MIT License (MIT)
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// </license>
#pragma once
// Constants
//
#ifndef E_NOTFOUND
#define E_NOTFOUND HRESULT_FROM_WIN32(ERROR_NOT_FOUND)
#endif
#ifndef E_FILENOTFOUND
#define E_FILENOTFOUND HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
#endif
// Enumerations
//
/// <summary>
/// The state of an instance.
/// </summary>
enum InstanceState : unsigned {
/// <summary>
/// The instance state has not been determined.
/// </summary>
eNone = 0,
/// <summary>
/// The instance installation path exists.
/// </summary>
eLocal = 1,
/// <summary>
/// A product is registered to the instance.
/// </summary>
eRegistered = 2,
/// <summary>
/// No reboot is required for the instance.
/// </summary>
eNoRebootRequired = 4,
/// <summary>
/// The instance represents a complete install.
/// </summary>
eComplete = MAXUINT,
};
// Forward interface declarations
//
#ifndef __ISetupInstance_FWD_DEFINED__
#define __ISetupInstance_FWD_DEFINED__
typedef struct ISetupInstance ISetupInstance;
#endif
#ifndef __ISetupInstance2_FWD_DEFINED__
#define __ISetupInstance2_FWD_DEFINED__
typedef struct ISetupInstance2 ISetupInstance2;
#endif
#ifndef __IEnumSetupInstances_FWD_DEFINED__
#define __IEnumSetupInstances_FWD_DEFINED__
typedef struct IEnumSetupInstances IEnumSetupInstances;
#endif
#ifndef __ISetupConfiguration_FWD_DEFINED__
#define __ISetupConfiguration_FWD_DEFINED__
typedef struct ISetupConfiguration ISetupConfiguration;
#endif
#ifndef __ISetupConfiguration2_FWD_DEFINED__
#define __ISetupConfiguration2_FWD_DEFINED__
typedef struct ISetupConfiguration2 ISetupConfiguration2;
#endif
#ifndef __ISetupPackageReference_FWD_DEFINED__
#define __ISetupPackageReference_FWD_DEFINED__
typedef struct ISetupPackageReference ISetupPackageReference;
#endif
#ifndef __ISetupHelper_FWD_DEFINED__
#define __ISetupHelper_FWD_DEFINED__
typedef struct ISetupHelper ISetupHelper;
#endif
// Forward class declarations
//
#ifndef __SetupConfiguration_FWD_DEFINED__
#define __SetupConfiguration_FWD_DEFINED__
#ifdef __cplusplus
typedef class SetupConfiguration SetupConfiguration;
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
// Interface definitions
//
EXTERN_C const IID IID_ISetupInstance;
#if defined(__cplusplus) && !defined(CINTERFACE)
/// <summary>
/// Information about an instance of a product.
/// </summary>
struct DECLSPEC_UUID("B41463C3-8866-43B5-BC33-2B0676F7F42E")
DECLSPEC_NOVTABLE ISetupInstance : public IUnknown {
/// <summary>
/// Gets the instance identifier (should match the name of the parent instance
/// directory).
/// </summary>
/// <param name="pbstrInstanceId">The instance identifier.</param>
/// <returns>Standard HRESULT indicating success or failure, including
/// E_FILENOTFOUND if the instance state does not exist.</returns>
STDMETHOD(GetInstanceId)(_Out_ BSTR *pbstrInstanceId) = 0;
/// <summary>
/// Gets the local date and time when the installation was originally
/// installed.
/// </summary>
/// <param name="pInstallDate">The local date and time when the installation
/// was originally installed.</param>
/// <returns>Standard HRESULT indicating success or failure, including
/// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
/// property is not defined.</returns>
STDMETHOD(GetInstallDate)(_Out_ LPFILETIME pInstallDate) = 0;
/// <summary>
/// Gets the unique name of the installation, often indicating the branch and
/// other information used for telemetry.
/// </summary>
/// <param name="pbstrInstallationName">The unique name of the installation,
/// often indicating the branch and other information used for
/// telemetry.</param>
/// <returns>Standard HRESULT indicating success or failure, including
/// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
/// property is not defined.</returns>
STDMETHOD(GetInstallationName)(_Out_ BSTR *pbstrInstallationName) = 0;
/// <summary>
/// Gets the path to the installation root of the product.
/// </summary>
/// <param name="pbstrInstallationPath">The path to the installation root of
/// the product.</param>
/// <returns>Standard HRESULT indicating success or failure, including
/// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
/// property is not defined.</returns>
STDMETHOD(GetInstallationPath)(_Out_ BSTR *pbstrInstallationPath) = 0;
/// <summary>
/// Gets the version of the product installed in this instance.
/// </summary>
/// <param name="pbstrInstallationVersion">The version of the product
/// installed in this instance.</param>
/// <returns>Standard HRESULT indicating success or failure, including
/// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
/// property is not defined.</returns>
STDMETHOD(GetInstallationVersion)(_Out_ BSTR *pbstrInstallationVersion) = 0;
/// <summary>
/// Gets the display name (title) of the product installed in this instance.
/// </summary>
/// <param name="lcid">The LCID for the display name.</param>
/// <param name="pbstrDisplayName">The display name (title) of the product
/// installed in this instance.</param>
/// <returns>Standard HRESULT indicating success or failure, including
/// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
/// property is not defined.</returns>
STDMETHOD(GetDisplayName)(_In_ LCID lcid, _Out_ BSTR *pbstrDisplayName) = 0;
/// <summary>
/// Gets the description of the product installed in this instance.
/// </summary>
/// <param name="lcid">The LCID for the description.</param>
/// <param name="pbstrDescription">The description of the product installed in
/// this instance.</param>
/// <returns>Standard HRESULT indicating success or failure, including
/// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
/// property is not defined.</returns>
STDMETHOD(GetDescription)(_In_ LCID lcid, _Out_ BSTR *pbstrDescription) = 0;
/// <summary>
/// Resolves the optional relative path to the root path of the instance.
/// </summary>
/// <param name="pwszRelativePath">A relative path within the instance to
/// resolve, or NULL to get the root path.</param>
/// <param name="pbstrAbsolutePath">The full path to the optional relative
/// path within the instance. If the relative path is NULL, the root path will
/// always terminate in a backslash.</param>
/// <returns>Standard HRESULT indicating success or failure, including
/// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
/// property is not defined.</returns>
STDMETHOD(ResolvePath)
(_In_opt_z_ LPCOLESTR pwszRelativePath, _Out_ BSTR *pbstrAbsolutePath) = 0;
};
#endif
EXTERN_C const IID IID_ISetupInstance2;
#if defined(__cplusplus) && !defined(CINTERFACE)
/// <summary>
/// Information about an instance of a product.
/// </summary>
struct DECLSPEC_UUID("89143C9A-05AF-49B0-B717-72E218A2185C")
DECLSPEC_NOVTABLE ISetupInstance2 : public ISetupInstance {
/// <summary>
/// Gets the state of the instance.
/// </summary>
/// <param name="pState">The state of the instance.</param>
/// <returns>Standard HRESULT indicating success or failure, including
/// E_FILENOTFOUND if the instance state does not exist.</returns>
STDMETHOD(GetState)(_Out_ InstanceState *pState) = 0;
/// <summary>
/// Gets an array of package references registered to the instance.
/// </summary>
/// <param name="ppsaPackages">Pointer to an array of <see
/// cref="ISetupPackageReference"/>.</param>
/// <returns>Standard HRESULT indicating success or failure, including
/// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
/// packages property is not defined.</returns>
STDMETHOD(GetPackages)(_Out_ LPSAFEARRAY *ppsaPackages) = 0;
/// <summary>
/// Gets a pointer to the <see cref="ISetupPackageReference"/> that represents
/// the registered product.
/// </summary>
/// <param name="ppPackage">Pointer to an instance of <see
/// cref="ISetupPackageReference"/>. This may be NULL if <see
/// cref="GetState"/> does not return <see cref="eComplete"/>.</param>
/// <returns>Standard HRESULT indicating success or failure, including
/// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
/// packages property is not defined.</returns>
STDMETHOD(GetProduct)
(_Outptr_result_maybenull_ ISetupPackageReference **ppPackage) = 0;
/// <summary>
/// Gets the relative path to the product application, if available.
/// </summary>
/// <param name="pbstrProductPath">The relative path to the product
/// application, if available.</param>
/// <returns>Standard HRESULT indicating success or failure, including
/// E_FILENOTFOUND if the instance state does not exist.</returns>
STDMETHOD(GetProductPath)
(_Outptr_result_maybenull_ BSTR *pbstrProductPath) = 0;
};
#endif
EXTERN_C const IID IID_IEnumSetupInstances;
#if defined(__cplusplus) && !defined(CINTERFACE)
/// <summary>
/// A enumerator of installed <see cref="ISetupInstance"/> objects.
/// </summary>
struct DECLSPEC_UUID("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848")
DECLSPEC_NOVTABLE IEnumSetupInstances : public IUnknown {
/// <summary>
/// Retrieves the next set of product instances in the enumeration sequence.
/// </summary>
/// <param name="celt">The number of product instances to retrieve.</param>
/// <param name="rgelt">A pointer to an array of <see
/// cref="ISetupInstance"/>.</param>
/// <param name="pceltFetched">A pointer to the number of product instances
/// retrieved. If celt is 1 this parameter may be NULL.</param>
/// <returns>S_OK if the number of elements were fetched, S_FALSE if nothing
/// was fetched (at end of enumeration), E_INVALIDARG if celt is greater than
/// 1 and pceltFetched is NULL, or E_OUTOFMEMORY if an <see
/// cref="ISetupInstance"/> could not be allocated.</returns>
STDMETHOD(Next)
(_In_ ULONG celt, _Out_writes_to_(celt, *pceltFetched) ISetupInstance **rgelt,
_Out_opt_ _Deref_out_range_(0, celt) ULONG *pceltFetched) = 0;
/// <summary>
/// Skips the next set of product instances in the enumeration sequence.
/// </summary>
/// <param name="celt">The number of product instances to skip.</param>
/// <returns>S_OK if the number of elements could be skipped; otherwise,
/// S_FALSE;</returns>
STDMETHOD(Skip)(_In_ ULONG celt) = 0;
/// <summary>
/// Resets the enumeration sequence to the beginning.
/// </summary>
/// <returns>Always returns S_OK;</returns>
STDMETHOD(Reset)(void) = 0;
/// <summary>
/// Creates a new enumeration object in the same state as the current
/// enumeration object: the new object points to the same place in the
/// enumeration sequence.
/// </summary>
/// <param name="ppenum">A pointer to a pointer to a new <see
/// cref="IEnumSetupInstances"/> interface. If the method fails, this
/// parameter is undefined.</param>
/// <returns>S_OK if a clone was returned; otherwise, E_OUTOFMEMORY.</returns>
STDMETHOD(Clone)(_Deref_out_opt_ IEnumSetupInstances **ppenum) = 0;
};
#endif
EXTERN_C const IID IID_ISetupConfiguration;
#if defined(__cplusplus) && !defined(CINTERFACE)
/// <summary>
/// Gets information about product instances set up on the machine.
/// </summary>
struct DECLSPEC_UUID("42843719-DB4C-46C2-8E7C-64F1816EFD5B")
DECLSPEC_NOVTABLE ISetupConfiguration : public IUnknown {
/// <summary>
/// Enumerates all completed product instances installed.
/// </summary>
/// <param name="ppEnumInstances">An enumeration of completed, installed
/// product instances.</param>
/// <returns>Standard HRESULT indicating success or failure.</returns>
STDMETHOD(EnumInstances)(_Out_ IEnumSetupInstances **ppEnumInstances) = 0;
/// <summary>
/// Gets the instance for the current process path.
/// </summary>
/// <param name="ppInstance">The instance for the current process
/// path.</param>
/// <returns>The instance for the current process path, or E_NOTFOUND if not
/// found.</returns>
STDMETHOD(GetInstanceForCurrentProcess)
(_Out_ ISetupInstance **ppInstance) = 0;
/// <summary>
/// Gets the instance for the given path.
/// </summary>
/// <param name="ppInstance">The instance for the given path.</param>
/// <returns>The instance for the given path, or E_NOTFOUND if not
/// found.</returns>
STDMETHOD(GetInstanceForPath)
(_In_z_ LPCWSTR wzPath, _Out_ ISetupInstance **ppInstance) = 0;
};
#endif
EXTERN_C const IID IID_ISetupConfiguration2;
#if defined(__cplusplus) && !defined(CINTERFACE)
/// <summary>
/// Gets information about product instances.
/// </summary>
struct DECLSPEC_UUID("26AAB78C-4A60-49D6-AF3B-3C35BC93365D")
DECLSPEC_NOVTABLE ISetupConfiguration2 : public ISetupConfiguration {
/// <summary>
/// Enumerates all product instances.
/// </summary>
/// <param name="ppEnumInstances">An enumeration of all product
/// instances.</param>
/// <returns>Standard HRESULT indicating success or failure.</returns>
STDMETHOD(EnumAllInstances)(_Out_ IEnumSetupInstances **ppEnumInstances) = 0;
};
#endif
EXTERN_C const IID IID_ISetupPackageReference;
#if defined(__cplusplus) && !defined(CINTERFACE)
/// <summary>
/// A reference to a package.
/// </summary>
struct DECLSPEC_UUID("da8d8a16-b2b6-4487-a2f1-594ccccd6bf5")
DECLSPEC_NOVTABLE ISetupPackageReference : public IUnknown {
/// <summary>
/// Gets the general package identifier.
/// </summary>
/// <param name="pbstrId">The general package identifier.</param>
/// <returns>Standard HRESULT indicating success or failure.</returns>
STDMETHOD(GetId)(_Out_ BSTR *pbstrId) = 0;
/// <summary>
/// Gets the version of the package.
/// </summary>
/// <param name="pbstrVersion">The version of the package.</param>
/// <returns>Standard HRESULT indicating success or failure.</returns>
STDMETHOD(GetVersion)(_Out_ BSTR *pbstrVersion) = 0;
/// <summary>
/// Gets the target process architecture of the package.
/// </summary>
/// <param name="pbstrChip">The target process architecture of the
/// package.</param>
/// <returns>Standard HRESULT indicating success or failure.</returns>
STDMETHOD(GetChip)(_Out_ BSTR *pbstrChip) = 0;
/// <summary>
/// Gets the language and optional region identifier.
/// </summary>
/// <param name="pbstrLanguage">The language and optional region
/// identifier.</param>
/// <returns>Standard HRESULT indicating success or failure.</returns>
STDMETHOD(GetLanguage)(_Out_ BSTR *pbstrLanguage) = 0;
/// <summary>
/// Gets the build branch of the package.
/// </summary>
/// <param name="pbstrBranch">The build branch of the package.</param>
/// <returns>Standard HRESULT indicating success or failure.</returns>
STDMETHOD(GetBranch)(_Out_ BSTR *pbstrBranch) = 0;
/// <summary>
/// Gets the type of the package.
/// </summary>
/// <param name="pbstrType">The type of the package.</param>
/// <returns>Standard HRESULT indicating success or failure.</returns>
STDMETHOD(GetType)(_Out_ BSTR *pbstrType) = 0;
/// <summary>
/// Gets the unique identifier consisting of all defined tokens.
/// </summary>
/// <param name="pbstrUniqueId">The unique identifier consisting of all
/// defined tokens.</param>
/// <returns>Standard HRESULT indicating success or failure, including
/// E_UNEXPECTED if no Id was defined (required).</returns>
STDMETHOD(GetUniqueId)(_Out_ BSTR *pbstrUniqueId) = 0;
};
#endif
EXTERN_C const IID IID_ISetupHelper;
#if defined(__cplusplus) && !defined(CINTERFACE)
/// <summary>
/// Helper functions.
/// </summary>
/// <remarks>
/// You can query for this interface from the <see cref="SetupConfiguration"/>
/// class.
/// </remarks>
struct DECLSPEC_UUID("42b21b78-6192-463e-87bf-d577838f1d5c")
DECLSPEC_NOVTABLE ISetupHelper : public IUnknown {
/// <summary>
/// Parses a dotted quad version string into a 64-bit unsigned integer.
/// </summary>
/// <param name="pwszVersion">The dotted quad version string to parse, e.g.
/// 1.2.3.4.</param>
/// <param name="pullVersion">A 64-bit unsigned integer representing the
/// version. You can compare this to other versions.</param>
/// <returns>Standard HRESULT indicating success or failure.</returns>
STDMETHOD(ParseVersion)
(_In_ LPCOLESTR pwszVersion, _Out_ PULONGLONG pullVersion) = 0;
/// <summary>
/// Parses a dotted quad version string into a 64-bit unsigned integer.
/// </summary>
/// <param name="pwszVersionRange">The string containing 1 or 2 dotted quad
/// version strings to parse, e.g. [1.0,) that means 1.0.0.0 or newer.</param>
/// <param name="pullMinVersion">A 64-bit unsigned integer representing the
/// minimum version, which may be 0. You can compare this to other
/// versions.</param>
/// <param name="pullMaxVersion">A 64-bit unsigned integer representing the
/// maximum version, which may be MAXULONGLONG. You can compare this to other
/// versions.</param>
/// <returns>Standard HRESULT indicating success or failure.</returns>
STDMETHOD(ParseVersionRange)
(_In_ LPCOLESTR pwszVersionRange, _Out_ PULONGLONG pullMinVersion,
_Out_ PULONGLONG pullMaxVersion) = 0;
};
#endif
// Class declarations
//
EXTERN_C const CLSID CLSID_SetupConfiguration;
#ifdef __cplusplus
/// <summary>
/// This class implements <see cref="ISetupConfiguration"/>, <see
/// cref="ISetupConfiguration2"/>, and <see cref="ISetupHelper"/>.
/// </summary>
class DECLSPEC_UUID("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D") SetupConfiguration;
#endif
// Function declarations
//
/// <summary>
/// Gets an <see cref="ISetupConfiguration"/> that provides information about
/// product instances installed on the machine.
/// </summary>
/// <param name="ppConfiguration">The <see cref="ISetupConfiguration"/> that
/// provides information about product instances installed on the
/// machine.</param>
/// <param name="pReserved">Reserved for future use.</param>
/// <returns>Standard HRESULT indicating success or failure.</returns>
STDMETHODIMP GetSetupConfiguration(_Out_ ISetupConfiguration **ppConfiguration,
_Reserved_ LPVOID pReserved);
#ifdef __cplusplus
}
#endif

View File

@ -13,7 +13,6 @@
// be clueless and will emit "argument unused" warnings. If PR17239 is properly
// fixed, this should not happen because the "/link" option is restricted to
// consume only remaining args in its response file.
// ARGS-NOT: warning
// ARGS-NOT: argument unused during compilation
// Identify the linker command
// ARGS: link.exe