in platforms/Windows/CustomActions/SwiftInstaller/Sources/swift_installer.cc [163:269]
std::vector<std::filesystem::path> available_toolsets() noexcept {
windows::raii::com_initializer com;
std::vector<std::filesystem::path> toolsets;
ISetupConfigurationPtr configuration;
if (FAILED(configuration.CreateInstance(__uuidof(SetupConfiguration))))
return toolsets;
ISetupConfiguration2Ptr configuration2;
if (FAILED(configuration->QueryInterface(&configuration2)))
return toolsets;
IEnumSetupInstancesPtr instances;
if (FAILED(configuration2->EnumAllInstances(&instances)))
return toolsets;
ULONG fetched;
ISetupInstancePtr instance;
while (SUCCEEDED(instances->Next(1, &instance, &fetched)) && fetched) {
ISetupInstance2Ptr instance2;
if (FAILED(instance->QueryInterface(&instance2)))
continue;
InstanceState state;
if (FAILED(instance2->GetState(&state)))
continue;
// Ensure that the instance state matches
// eLocal: The instance installation path exists.
// eRegistered: A product is registered to the instance.
if (~state & eLocal or ~state & eRegistered)
continue;
LPSAFEARRAY packages;
if (FAILED(instance2->GetPackages(&packages)))
continue;
LONG lower, upper;
if (FAILED(SafeArrayGetLBound(packages, 1, &lower)) ||
FAILED(SafeArrayGetUBound(packages, 1, &upper)))
continue;
for (LONG index = 0, count = upper - lower + 1; index < count; ++index) {
IUnknownPtr element;
if (FAILED(SafeArrayGetElement(packages, &index, &element)))
continue;
ISetupPackageReferencePtr package;
if (FAILED(element->QueryInterface(&package)))
continue;
_bstr_t package_id;
if (FAILED(package->GetId(package_id.GetAddress())))
continue;
// Ensure that we are dealing with a (known) MSVC ToolSet
if (std::none_of(std::begin(known_toolsets), std::end(known_toolsets),
[package_id = package_id.GetBSTR()](const wchar_t *id) {
return wcscmp(package_id, id) == 0;
}))
continue;
_bstr_t VSInstallDir;
if (FAILED(instance2->GetInstallationPath(VSInstallDir.GetAddress())))
continue;
std::filesystem::path VCInstallDir{static_cast<wchar_t *>(VSInstallDir)};
VCInstallDir.append("VC");
std::string VCToolsVersion;
// VSInstallDir\VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt
// contains the default version of the v141 MSVC toolset. Prefer to use
// VSInstallDir\VC\Auxiliary\Build\Microsoft.VCToolsVersion.v142.default.txt
// which contains the default v142 version of the toolset.
for (const auto &file : {"Microsoft.VCToolsVersion.v142.default.txt",
"Microsoft.VCToolsVersion.default.txt"}) {
std::filesystem::path path{VCInstallDir};
path.append("Auxiliary");
path.append("Build");
path.append(file);
VCToolsVersion = contents(path);
// Strip any line ending characters from the contents of the file.
trim(VCToolsVersion);
if (!VCToolsVersion.empty())
break;
}
if (VCToolsVersion.empty())
continue;
std::filesystem::path VCToolsInstallDir{VCInstallDir};
VCToolsInstallDir.append("Tools");
VCToolsInstallDir.append("MSVC");
VCToolsInstallDir.append(VCToolsVersion);
// FIXME(compnerd) should we actually just walk the directory structure
// instead and populate all the toolsets? That would match roughly what
// we do with the UCRT currently.
toolsets.push_back(VCToolsInstallDir);
}
}
return toolsets;
}