Index: cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td @@ -283,4 +283,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 warn_drv_msvc_not_found : Warning< + "unable to find a Visual Studio installation; " + "try running Clang from a developer command prompt">, + InGroup; } Index: cfe/trunk/lib/Driver/ToolChains/MSVC.h =================================================================== --- cfe/trunk/lib/Driver/ToolChains/MSVC.h +++ cfe/trunk/lib/Driver/ToolChains/MSVC.h @@ -78,6 +78,22 @@ 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 @@ 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 @@ Tool *buildLinker() const override; Tool *buildAssembler() const override; private: - VersionTuple getMSVCVersionFromTriple() const; - VersionTuple getMSVCVersionFromExe() const; - + std::string VCToolChainPath; + bool IsVS2017OrNewer; CudaInstallationDetector CudaInstallation; }; Index: cfe/trunk/lib/Driver/ToolChains/MSVC.cpp =================================================================== --- cfe/trunk/lib/Driver/ToolChains/MSVC.cpp +++ cfe/trunk/lib/Driver/ToolChains/MSVC.cpp @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// -#include "Darwin.h" #include "MSVC.h" #include "CommonArgs.h" +#include "Darwin.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Version.h" #include "clang/Driver/Compilation.h" @@ -25,6 +25,8 @@ #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include @@ -42,6 +44,18 @@ #define NOMINMAX #endif #include + +// Make sure this comes before MSVCSetupApi.h +#include + +#include "MSVCSetupApi.h" +#include "llvm/Support/COM.h" +_COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration)); +_COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2)); +_COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper)); +_COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances)); +_COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance)); +_COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2)); #endif using namespace clang::driver; @@ -50,24 +64,232 @@ using namespace clang; using namespace llvm::opt; +// Defined below. +// Forward declare this so there aren't too many things above the constructor. +static bool getSystemRegistryString(const char *keyPath, const char *valueName, + std::string &value, std::string *phValue); + +// Check various environment variables to try and find a toolchain. +static bool findVCToolChainViaEnvironment(std::string &Path, + bool &IsVS2017OrNewer) { + // These variables are typically set by vcvarsall.bat + // when launching a developer command prompt. + if (llvm::Optional 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 that we find. + if (llvm::Optional PathEnv = + llvm::sys::Process::GetEnv("PATH")) { + llvm::SmallVector 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 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(TC); - std::string visualStudioBinDir; - if (MSVC.getVisualStudioBinariesFolder(ClangProgramPath, - visualStudioBinDir)) { - SmallString<128> FilePath(visualStudioBinDir); - llvm::sys::path::append(FilePath, Exe); - if (llvm::sys::fs::can_execute(FilePath.c_str())) - return FilePath.str(); - } - - return Exe; + SmallString<128> FilePath(MSVC.getSubDirectoryPath( + toolchains::MSVCToolChain::SubDirectoryType::Bin)); + llvm::sys::path::append(FilePath, Exe); + return llvm::sys::fs::can_execute(FilePath) ? FilePath.str() : Exe; } void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -76,7 +298,8 @@ const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; - const ToolChain &TC = getToolChain(); + + auto &TC = static_cast(getToolChain()); assert((Output.isFilename() || Output.isNothing()) && "invalid output"); if (Output.isFilename()) @@ -92,37 +315,20 @@ // did not run vcvarsall), try to build a consistent link environment. If // the environment variable is set however, assume the user knows what // they're doing. - std::string VisualStudioDir; - const auto &MSVC = static_cast(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)); - } + CmdArgs.push_back(Args.MakeArgString( + Twine("-libpath:") + + TC.getSubDirectoryPath( + toolchains::MSVCToolChain::SubDirectoryType::Lib))); + + if (TC.useUniversalCRT()) { + std::string UniversalCRTLibPath; + if (TC.getUniversalCRTLibraryPath(UniversalCRTLibPath)) + CmdArgs.push_back( + Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath)); } std::string WindowsSdkLibPath; - if (MSVC.getWindowsSDKLibraryPath(WindowsSdkLibPath)) + if (TC.getWindowsSDKLibraryPath(WindowsSdkLibPath)) CmdArgs.push_back( Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath)); } @@ -247,8 +453,7 @@ // If we're using the MSVC linker, it's not sufficient to just use link // from the program PATH, because other environments like GnuWin32 install // their own link.exe which may come first. - linkPath = FindVisualStudioExecutable(TC, "link.exe", - C.getDriver().getClangProgramPath()); + linkPath = FindVisualStudioExecutable(TC, "link.exe"); } else { linkPath = Linker; llvm::sys::path::replace_extension(linkPath, "exe"); @@ -381,9 +586,7 @@ Args.MakeArgString(std::string("/Fo") + Output.getFilename()); CmdArgs.push_back(Fo); - const Driver &D = getToolChain().getDriver(); - std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe", - D.getClangProgramPath()); + std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe"); return llvm::make_unique(JA, *this, Args.MakeArgString(Exec), CmdArgs, Inputs); } @@ -394,9 +597,19 @@ getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); + + // Check the environment first, since that's probably the user telling us + // what they want to use. + // Failing that, just try to find the newest Visual Studio version we can + // and use its default VC toolchain. + findVCToolChainViaEnvironment(VCToolChainPath, IsVS2017OrNewer) || + findVCToolChainViaSetupConfig(VCToolChainPath, IsVS2017OrNewer) || + findVCToolChainViaRegistry(VCToolChainPath, IsVS2017OrNewer); } Tool *MSVCToolChain::buildLinker() const { + if (VCToolChainPath.empty()) + getDriver().Diag(clang::diag::warn_drv_msvc_not_found); return new tools::visualstudio::Linker(*this); } @@ -444,6 +657,72 @@ CudaInstallation.print(OS); } +// Windows SDKs and VC Toolchains group their contents into subdirectories based +// on the target architecture. This function converts an llvm::Triple::ArchType +// to the corresponding subdirectory name. +static const char *llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch) { + using ArchType = llvm::Triple::ArchType; + switch (Arch) { + case ArchType::x86: + return "x86"; + case ArchType::x86_64: + return "x64"; + case ArchType::arm: + return "arm"; + default: + return ""; + } +} + +// Similar to the above function, but for Visual Studios before VS2017. +static const char *llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch) { + using ArchType = llvm::Triple::ArchType; + switch (Arch) { + case ArchType::x86: + // x86 is default in legacy VC toolchains. + // e.g. x86 libs are directly in /lib as opposed to /lib/x86. + return ""; + case ArchType::x86_64: + return "amd64"; + case ArchType::arm: + return "arm"; + default: + return ""; + } +} + +// Get the path to a specific subdirectory in the current toolchain for +// a given target architecture. +// VS2017 changed the VC toolchain layout, so this should be used instead +// of hardcoding paths. +std::string +MSVCToolChain::getSubDirectoryPath(SubDirectoryType Type, + llvm::Triple::ArchType TargetArch) const { + llvm::SmallString<256> Path(VCToolChainPath); + switch (Type) { + case SubDirectoryType::Bin: + if (IsVS2017OrNewer) { + bool HostIsX64 = + llvm::Triple(llvm::sys::getProcessTriple()).isArch64Bit(); + llvm::sys::path::append(Path, "bin", (HostIsX64 ? "HostX64" : "HostX86"), + llvmArchToWindowsSDKArch(TargetArch)); + + } else { + llvm::sys::path::append(Path, "bin", llvmArchToLegacyVCArch(TargetArch)); + } + break; + case SubDirectoryType::Include: + llvm::sys::path::append(Path, "include"); + break; + case SubDirectoryType::Lib: + llvm::sys::path::append( + Path, "lib", IsVS2017OrNewer ? llvmArchToWindowsSDKArch(TargetArch) + : llvmArchToLegacyVCArch(TargetArch)); + break; + } + return Path.str(); +} + #ifdef USE_WIN32 static bool readFullStringValue(HKEY hkey, const char *valueName, std::string &value) { @@ -573,27 +852,12 @@ #endif // USE_WIN32 } -// Convert LLVM's ArchType -// to the corresponding name of Windows SDK libraries subfolder -static StringRef getWindowsSDKArch(llvm::Triple::ArchType Arch) { - switch (Arch) { - case llvm::Triple::x86: - return "x86"; - case llvm::Triple::x86_64: - return "x64"; - case llvm::Triple::arm: - return "arm"; - default: - return ""; - } -} - // Find the most recent version of Universal CRT or Windows 10 SDK. // vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include // directory by name and uses the last one of the list. // So we compare entry names lexicographically to find the greatest one. -static bool getWindows10SDKVersion(const std::string &SDKPath, - std::string &SDKVersion) { +static bool getWindows10SDKVersionFromPath(const std::string &SDKPath, + std::string &SDKVersion) { SDKVersion.clear(); std::error_code EC; @@ -617,9 +881,9 @@ } /// \brief Get Windows SDK installation directory. -bool MSVCToolChain::getWindowsSDKDir(std::string &Path, int &Major, - std::string &WindowsSDKIncludeVersion, - std::string &WindowsSDKLibVersion) const { +static bool getWindowsSDKDir(std::string &Path, int &Major, + std::string &WindowsSDKIncludeVersion, + std::string &WindowsSDKLibVersion) { std::string RegistrySDKVersion; // Try the Windows registry. if (!getSystemRegistryString( @@ -651,7 +915,7 @@ return !WindowsSDKLibVersion.empty(); } if (Major == 10) { - if (!getWindows10SDKVersion(Path, WindowsSDKIncludeVersion)) + if (!getWindows10SDKVersionFromPath(Path, WindowsSDKIncludeVersion)) return false; WindowsSDKLibVersion = WindowsSDKIncludeVersion; return true; @@ -674,7 +938,10 @@ llvm::SmallString<128> libPath(sdkPath); llvm::sys::path::append(libPath, "Lib"); - if (sdkMajor <= 7) { + if (sdkMajor >= 8) { + llvm::sys::path::append(libPath, windowsSDKLibVersion, "um", + llvmArchToWindowsSDKArch(getArch())); + } else { switch (getArch()) { // In Windows SDK 7.x, x86 libraries are directly in the Lib folder. case llvm::Triple::x86: @@ -688,11 +955,6 @@ default: return false; } - } else { - const StringRef archName = getWindowsSDKArch(getArch()); - if (archName.empty()) - return false; - llvm::sys::path::append(libPath, windowsSDKLibVersion, "um", archName); } path = libPath.str(); @@ -701,16 +963,14 @@ // Check if the Include path of a specified version of Visual Studio contains // specific header files. If not, they are probably shipped with Universal CRT. -bool clang::driver::toolchains::MSVCToolChain::useUniversalCRT( - std::string &VisualStudioDir) const { - llvm::SmallString<128> TestPath(VisualStudioDir); - llvm::sys::path::append(TestPath, "VC\\include\\stdlib.h"); - +bool MSVCToolChain::useUniversalCRT() const { + llvm::SmallString<128> TestPath( + getSubDirectoryPath(SubDirectoryType::Include)); + llvm::sys::path::append(TestPath, "stdlib.h"); return !llvm::sys::fs::exists(TestPath); } -bool MSVCToolChain::getUniversalCRTSdkDir(std::string &Path, - std::string &UCRTVersion) const { +static bool getUniversalCRTSdkDir(std::string &Path, std::string &UCRTVersion) { // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry // for the specific key "KitsRoot10". So do we. if (!getSystemRegistryString( @@ -718,7 +978,7 @@ Path, nullptr)) return false; - return getWindows10SDKVersion(Path, UCRTVersion); + return getWindows10SDKVersionFromPath(Path, UCRTVersion); } bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const { @@ -729,7 +989,7 @@ if (!getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) return false; - StringRef ArchName = getWindowsSDKArch(getArch()); + StringRef ArchName = llvmArchToWindowsSDKArch(getArch()); if (ArchName.empty()) return false; @@ -740,104 +1000,18 @@ return true; } -// Get the location to use for Visual Studio binaries. The location priority -// is: %VCINSTALLDIR% > %PATH% > newest copy of Visual Studio installed on -// system (as reported by the registry). -bool MSVCToolChain::getVisualStudioBinariesFolder(const char *clangProgramPath, - std::string &path) const { - path.clear(); - - SmallString<128> BinDir; - - // First check the environment variables that vsvars32.bat sets. - llvm::Optional 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 { +static VersionTuple getMSVCVersionFromTriple(const llvm::Triple &Triple) { unsigned Major, Minor, Micro; - getTriple().getEnvironmentVersion(Major, Minor, Micro); + Triple.getEnvironmentVersion(Major, Minor, Micro); if (Major || Minor || Micro) return VersionTuple(Major, Minor, Micro); return VersionTuple(); } -VersionTuple MSVCToolChain::getMSVCVersionFromExe() const { +static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) { VersionTuple Version; #ifdef USE_WIN32 - std::string BinPath; - if (!getVisualStudioBinariesFolder("", BinPath)) - return Version; - SmallString<128> ClExe(BinPath); + SmallString<128> ClExe(BinDir); llvm::sys::path::append(ClExe, "cl.exe"); std::wstring ClExeWide; @@ -870,62 +1044,6 @@ return Version; } -// Get Visual Studio installation directory. -bool MSVCToolChain::getVisualStudioInstallDir(std::string &path) const { - // First check the environment variables that vsvars32.bat sets. - if (llvm::Optional 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, @@ -964,14 +1082,13 @@ return; } - std::string VSDir; - // When built with access to the proper Windows APIs, try to actually find // the correct include paths first. - if (getVisualStudioInstallDir(VSDir)) { - AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, VSDir, "VC\\include"); + if (!VCToolChainPath.empty()) { + addSystemInclude(DriverArgs, CC1Args, + getSubDirectoryPath(SubDirectoryType::Include)); - if (useUniversalCRT(VSDir)) { + if (useUniversalCRT()) { std::string UniversalCRTSdkPath; std::string UCRTVersion; if (getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) { @@ -1002,9 +1119,8 @@ AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, "include"); } - } else { - addSystemInclude(DriverArgs, CC1Args, VSDir); } + return; } @@ -1031,8 +1147,10 @@ const ArgList &Args) const { bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment(); VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args); - if (MSVT.empty()) MSVT = getMSVCVersionFromTriple(); - if (MSVT.empty() && IsWindowsMSVC) MSVT = getMSVCVersionFromExe(); + if (MSVT.empty()) + MSVT = getMSVCVersionFromTriple(getTriple()); + if (MSVT.empty() && IsWindowsMSVC) + MSVT = getMSVCVersionFromExe(getSubDirectoryPath(SubDirectoryType::Bin)); if (MSVT.empty() && Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, IsWindowsMSVC)) { Index: cfe/trunk/lib/Driver/ToolChains/MSVCSetupApi.h =================================================================== --- cfe/trunk/lib/Driver/ToolChains/MSVCSetupApi.h +++ cfe/trunk/lib/Driver/ToolChains/MSVCSetupApi.h @@ -0,0 +1,514 @@ +// +// Copyright (C) Microsoft Corporation. All rights reserved. +// Licensed under the MIT 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. +// + +#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 +// +/// +/// The state of an instance. +/// +enum InstanceState : unsigned { + /// + /// The instance state has not been determined. + /// + eNone = 0, + + /// + /// The instance installation path exists. + /// + eLocal = 1, + + /// + /// A product is registered to the instance. + /// + eRegistered = 2, + + /// + /// No reboot is required for the instance. + /// + eNoRebootRequired = 4, + + /// + /// The instance represents a complete install. + /// + 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) +/// +/// Information about an instance of a product. +/// +struct DECLSPEC_UUID("B41463C3-8866-43B5-BC33-2B0676F7F42E") + DECLSPEC_NOVTABLE ISetupInstance : public IUnknown { + /// + /// Gets the instance identifier (should match the name of the parent instance + /// directory). + /// + /// The instance identifier. + /// Standard HRESULT indicating success or failure, including + /// E_FILENOTFOUND if the instance state does not exist. + STDMETHOD(GetInstanceId)(_Out_ BSTR *pbstrInstanceId) = 0; + + /// + /// Gets the local date and time when the installation was originally + /// installed. + /// + /// The local date and time when the installation + /// was originally installed. + /// 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. + STDMETHOD(GetInstallDate)(_Out_ LPFILETIME pInstallDate) = 0; + + /// + /// Gets the unique name of the installation, often indicating the branch and + /// other information used for telemetry. + /// + /// The unique name of the installation, + /// often indicating the branch and other information used for + /// telemetry. + /// 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. + STDMETHOD(GetInstallationName)(_Out_ BSTR *pbstrInstallationName) = 0; + + /// + /// Gets the path to the installation root of the product. + /// + /// The path to the installation root of + /// the product. + /// 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. + STDMETHOD(GetInstallationPath)(_Out_ BSTR *pbstrInstallationPath) = 0; + + /// + /// Gets the version of the product installed in this instance. + /// + /// The version of the product + /// installed in this instance. + /// 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. + STDMETHOD(GetInstallationVersion)(_Out_ BSTR *pbstrInstallationVersion) = 0; + + /// + /// Gets the display name (title) of the product installed in this instance. + /// + /// The LCID for the display name. + /// The display name (title) of the product + /// installed in this instance. + /// 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. + STDMETHOD(GetDisplayName)(_In_ LCID lcid, _Out_ BSTR *pbstrDisplayName) = 0; + + /// + /// Gets the description of the product installed in this instance. + /// + /// The LCID for the description. + /// The description of the product installed in + /// this instance. + /// 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. + STDMETHOD(GetDescription)(_In_ LCID lcid, _Out_ BSTR *pbstrDescription) = 0; + + /// + /// Resolves the optional relative path to the root path of the instance. + /// + /// A relative path within the instance to + /// resolve, or NULL to get the root path. + /// 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. + /// 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. + STDMETHOD(ResolvePath) + (_In_opt_z_ LPCOLESTR pwszRelativePath, _Out_ BSTR *pbstrAbsolutePath) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupInstance2; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Information about an instance of a product. +/// +struct DECLSPEC_UUID("89143C9A-05AF-49B0-B717-72E218A2185C") + DECLSPEC_NOVTABLE ISetupInstance2 : public ISetupInstance { + /// + /// Gets the state of the instance. + /// + /// The state of the instance. + /// Standard HRESULT indicating success or failure, including + /// E_FILENOTFOUND if the instance state does not exist. + STDMETHOD(GetState)(_Out_ InstanceState *pState) = 0; + + /// + /// Gets an array of package references registered to the instance. + /// + /// Pointer to an array of . + /// 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. + STDMETHOD(GetPackages)(_Out_ LPSAFEARRAY *ppsaPackages) = 0; + + /// + /// Gets a pointer to the that represents + /// the registered product. + /// + /// Pointer to an instance of . This may be NULL if does not return . + /// 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. + STDMETHOD(GetProduct) + (_Outptr_result_maybenull_ ISetupPackageReference **ppPackage) = 0; + + /// + /// Gets the relative path to the product application, if available. + /// + /// The relative path to the product + /// application, if available. + /// Standard HRESULT indicating success or failure, including + /// E_FILENOTFOUND if the instance state does not exist. + STDMETHOD(GetProductPath) + (_Outptr_result_maybenull_ BSTR *pbstrProductPath) = 0; +}; +#endif + +EXTERN_C const IID IID_IEnumSetupInstances; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// A enumerator of installed objects. +/// +struct DECLSPEC_UUID("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848") + DECLSPEC_NOVTABLE IEnumSetupInstances : public IUnknown { + /// + /// Retrieves the next set of product instances in the enumeration sequence. + /// + /// The number of product instances to retrieve. + /// A pointer to an array of . + /// A pointer to the number of product instances + /// retrieved. If celt is 1 this parameter may be NULL. + /// 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 could not be allocated. + STDMETHOD(Next) + (_In_ ULONG celt, _Out_writes_to_(celt, *pceltFetched) ISetupInstance **rgelt, + _Out_opt_ _Deref_out_range_(0, celt) ULONG *pceltFetched) = 0; + + /// + /// Skips the next set of product instances in the enumeration sequence. + /// + /// The number of product instances to skip. + /// S_OK if the number of elements could be skipped; otherwise, + /// S_FALSE; + STDMETHOD(Skip)(_In_ ULONG celt) = 0; + + /// + /// Resets the enumeration sequence to the beginning. + /// + /// Always returns S_OK; + STDMETHOD(Reset)(void) = 0; + + /// + /// 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. + /// + /// A pointer to a pointer to a new interface. If the method fails, this + /// parameter is undefined. + /// S_OK if a clone was returned; otherwise, E_OUTOFMEMORY. + STDMETHOD(Clone)(_Deref_out_opt_ IEnumSetupInstances **ppenum) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupConfiguration; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Gets information about product instances set up on the machine. +/// +struct DECLSPEC_UUID("42843719-DB4C-46C2-8E7C-64F1816EFD5B") + DECLSPEC_NOVTABLE ISetupConfiguration : public IUnknown { + /// + /// Enumerates all completed product instances installed. + /// + /// An enumeration of completed, installed + /// product instances. + /// Standard HRESULT indicating success or failure. + STDMETHOD(EnumInstances)(_Out_ IEnumSetupInstances **ppEnumInstances) = 0; + + /// + /// Gets the instance for the current process path. + /// + /// The instance for the current process + /// path. + /// The instance for the current process path, or E_NOTFOUND if not + /// found. + STDMETHOD(GetInstanceForCurrentProcess) + (_Out_ ISetupInstance **ppInstance) = 0; + + /// + /// Gets the instance for the given path. + /// + /// The instance for the given path. + /// The instance for the given path, or E_NOTFOUND if not + /// found. + STDMETHOD(GetInstanceForPath) + (_In_z_ LPCWSTR wzPath, _Out_ ISetupInstance **ppInstance) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupConfiguration2; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Gets information about product instances. +/// +struct DECLSPEC_UUID("26AAB78C-4A60-49D6-AF3B-3C35BC93365D") + DECLSPEC_NOVTABLE ISetupConfiguration2 : public ISetupConfiguration { + /// + /// Enumerates all product instances. + /// + /// An enumeration of all product + /// instances. + /// Standard HRESULT indicating success or failure. + STDMETHOD(EnumAllInstances)(_Out_ IEnumSetupInstances **ppEnumInstances) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupPackageReference; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// A reference to a package. +/// +struct DECLSPEC_UUID("da8d8a16-b2b6-4487-a2f1-594ccccd6bf5") + DECLSPEC_NOVTABLE ISetupPackageReference : public IUnknown { + /// + /// Gets the general package identifier. + /// + /// The general package identifier. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetId)(_Out_ BSTR *pbstrId) = 0; + + /// + /// Gets the version of the package. + /// + /// The version of the package. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetVersion)(_Out_ BSTR *pbstrVersion) = 0; + + /// + /// Gets the target process architecture of the package. + /// + /// The target process architecture of the + /// package. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetChip)(_Out_ BSTR *pbstrChip) = 0; + + /// + /// Gets the language and optional region identifier. + /// + /// The language and optional region + /// identifier. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetLanguage)(_Out_ BSTR *pbstrLanguage) = 0; + + /// + /// Gets the build branch of the package. + /// + /// The build branch of the package. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetBranch)(_Out_ BSTR *pbstrBranch) = 0; + + /// + /// Gets the type of the package. + /// + /// The type of the package. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetType)(_Out_ BSTR *pbstrType) = 0; + + /// + /// Gets the unique identifier consisting of all defined tokens. + /// + /// The unique identifier consisting of all + /// defined tokens. + /// Standard HRESULT indicating success or failure, including + /// E_UNEXPECTED if no Id was defined (required). + STDMETHOD(GetUniqueId)(_Out_ BSTR *pbstrUniqueId) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupHelper; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Helper functions. +/// +/// +/// You can query for this interface from the +/// class. +/// +struct DECLSPEC_UUID("42b21b78-6192-463e-87bf-d577838f1d5c") + DECLSPEC_NOVTABLE ISetupHelper : public IUnknown { + /// + /// Parses a dotted quad version string into a 64-bit unsigned integer. + /// + /// The dotted quad version string to parse, e.g. + /// 1.2.3.4. + /// A 64-bit unsigned integer representing the + /// version. You can compare this to other versions. + /// Standard HRESULT indicating success or failure. + STDMETHOD(ParseVersion) + (_In_ LPCOLESTR pwszVersion, _Out_ PULONGLONG pullVersion) = 0; + + /// + /// Parses a dotted quad version string into a 64-bit unsigned integer. + /// + /// The string containing 1 or 2 dotted quad + /// version strings to parse, e.g. [1.0,) that means 1.0.0.0 or newer. + /// A 64-bit unsigned integer representing the + /// minimum version, which may be 0. You can compare this to other + /// versions. + /// A 64-bit unsigned integer representing the + /// maximum version, which may be MAXULONGLONG. You can compare this to other + /// versions. + /// Standard HRESULT indicating success or failure. + STDMETHOD(ParseVersionRange) + (_In_ LPCOLESTR pwszVersionRange, _Out_ PULONGLONG pullMinVersion, + _Out_ PULONGLONG pullMaxVersion) = 0; +}; +#endif + +// Class declarations +// +EXTERN_C const CLSID CLSID_SetupConfiguration; + +#ifdef __cplusplus +/// +/// This class implements , , and . +/// +class DECLSPEC_UUID("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D") SetupConfiguration; +#endif + +// Function declarations +// +/// +/// Gets an that provides information about +/// product instances installed on the machine. +/// +/// The that +/// provides information about product instances installed on the +/// machine. +/// Reserved for future use. +/// Standard HRESULT indicating success or failure. +STDMETHODIMP GetSetupConfiguration(_Out_ ISetupConfiguration **ppConfiguration, + _Reserved_ LPVOID pReserved); + +#ifdef __cplusplus +} +#endif Index: cfe/trunk/test/Driver/cl-link-at-file.c =================================================================== --- cfe/trunk/test/Driver/cl-link-at-file.c +++ cfe/trunk/test/Driver/cl-link-at-file.c @@ -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