From 069cff63f62b76fedec9064240b4aa53f1d5c71f Mon Sep 17 00:00:00 2001 From: Niyas Sait Date: Sat, 9 Apr 2022 18:03:18 +0100 Subject: VS: refactor EnumerateAndChooseVSInstance Move all VS instance enumeration code using COM interface to EnumerateVSInstancesWithCOM --- Source/cmVSSetupHelper.cxx | 128 +++++++++++++++++++++++++-------------------- Source/cmVSSetupHelper.h | 1 + 2 files changed, 73 insertions(+), 56 deletions(-) diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx index cbd241b..49ad441 100644 --- a/Source/cmVSSetupHelper.cxx +++ b/Source/cmVSSetupHelper.cxx @@ -295,6 +295,39 @@ bool cmVSSetupAPIHelper::IsEWDKEnabled() return false; } +bool cmVSSetupAPIHelper::EnumerateVSInstancesWithCOM( + std::vector& VSInstances) +{ + if (initializationFailure || setupConfig == NULL || setupConfig2 == NULL || + setupHelper == NULL) + return false; + + SmartCOMPtr enumInstances = NULL; + if (FAILED( + setupConfig2->EnumInstances((IEnumSetupInstances**)&enumInstances)) || + !enumInstances) { + return false; + } + + SmartCOMPtr instance; + while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) { + SmartCOMPtr instance2 = NULL; + if (FAILED( + instance->QueryInterface(IID_ISetupInstance2, (void**)&instance2)) || + !instance2) { + instance = NULL; + continue; + } + + VSInstanceInfo instanceInfo; + bool isInstalled = GetVSInstanceInfo(instance2, instanceInfo); + instance = instance2 = NULL; + if (isInstalled) + VSInstances.push_back(instanceInfo); + } + return true; +} + bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() { bool isVSInstanceExists = false; @@ -321,10 +354,6 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() return true; } - if (initializationFailure || setupConfig == NULL || setupConfig2 == NULL || - setupHelper == NULL) - return false; - std::string envVSCommonToolsDir; std::string envVSCommonToolsDirEnvName = "VS" + std::to_string(this->Version) + "0COMNTOOLS"; @@ -334,72 +363,59 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() cmSystemTools::ConvertToUnixSlashes(envVSCommonToolsDir); } - std::vector vecVSInstances; - SmartCOMPtr enumInstances = NULL; - if (FAILED( - setupConfig2->EnumInstances((IEnumSetupInstances**)&enumInstances)) || - !enumInstances) { - return false; - } - std::string const wantVersion = std::to_string(this->Version) + '.'; bool specifiedLocationNotSpecifiedVersion = false; SmartCOMPtr instance; - while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) { - SmartCOMPtr instance2 = NULL; - if (FAILED( - instance->QueryInterface(IID_ISetupInstance2, (void**)&instance2)) || - !instance2) { - instance = NULL; + + std::vector vecVSInstancesAll; + + // Enumerate VS instances with COM interface + if (!EnumerateVSInstancesWithCOM(vecVSInstancesAll)) { + return false; + } + + std::vector vecVSInstances; + for (const auto& instanceInfo : vecVSInstancesAll) { + // We are looking for a specific major version. + if (instanceInfo.Version.size() < wantVersion.size() || + instanceInfo.Version.substr(0, wantVersion.size()) != wantVersion) { continue; } - VSInstanceInfo instanceInfo; - bool isInstalled = GetVSInstanceInfo(instance2, instanceInfo); - instance = instance2 = NULL; - - if (isInstalled) { - // We are looking for a specific major version. - if (instanceInfo.Version.size() < wantVersion.size() || - instanceInfo.Version.substr(0, wantVersion.size()) != wantVersion) { - continue; + if (!this->SpecifiedVSInstallLocation.empty()) { + // We are looking for a specific instance. + std::string currentVSLocation = instanceInfo.GetInstallLocation(); + if (cmSystemTools::ComparePath(currentVSLocation, + this->SpecifiedVSInstallLocation)) { + if (this->SpecifiedVSInstallVersion.empty() || + instanceInfo.Version == this->SpecifiedVSInstallVersion) { + chosenInstanceInfo = instanceInfo; + return true; + } + specifiedLocationNotSpecifiedVersion = true; } - - if (!this->SpecifiedVSInstallLocation.empty()) { - // We are looking for a specific instance. - std::string currentVSLocation = instanceInfo.GetInstallLocation(); + } else if (!this->SpecifiedVSInstallVersion.empty()) { + // We are looking for a specific version. + if (instanceInfo.Version == this->SpecifiedVSInstallVersion) { + chosenInstanceInfo = instanceInfo; + return true; + } + } else { + // We are not looking for a specific instance. + // If we've been given a hint then use it. + if (!envVSCommonToolsDir.empty()) { + std::string currentVSLocation = + cmStrCat(instanceInfo.GetInstallLocation(), "/Common7/Tools"); if (cmSystemTools::ComparePath(currentVSLocation, - this->SpecifiedVSInstallLocation)) { - if (this->SpecifiedVSInstallVersion.empty() || - instanceInfo.Version == this->SpecifiedVSInstallVersion) { - chosenInstanceInfo = instanceInfo; - return true; - } - specifiedLocationNotSpecifiedVersion = true; - } - } else if (!this->SpecifiedVSInstallVersion.empty()) { - // We are looking for a specific version. - if (instanceInfo.Version == this->SpecifiedVSInstallVersion) { + envVSCommonToolsDir)) { chosenInstanceInfo = instanceInfo; return true; } - } else { - // We are not looking for a specific instance. - // If we've been given a hint then use it. - if (!envVSCommonToolsDir.empty()) { - std::string currentVSLocation = - cmStrCat(instanceInfo.GetInstallLocation(), "/Common7/Tools"); - if (cmSystemTools::ComparePath(currentVSLocation, - envVSCommonToolsDir)) { - chosenInstanceInfo = instanceInfo; - return true; - } - } - // Otherwise, add this to the list of candidates. - vecVSInstances.push_back(instanceInfo); } + // Otherwise, add this to the list of candidates. + vecVSInstances.push_back(instanceInfo); } } diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h index 44c883b..e7a276e 100644 --- a/Source/cmVSSetupHelper.h +++ b/Source/cmVSSetupHelper.h @@ -118,6 +118,7 @@ private: int ChooseVSInstance(const std::vector& vecVSInstances); bool EnumerateAndChooseVSInstance(); bool LoadSpecifiedVSInstanceFromDisk(); + bool EnumerateVSInstancesWithCOM(std::vector& VSInstances); unsigned int Version; -- cgit v0.12 From f85913fa088f03532ac791735c24d25937b93c7b Mon Sep 17 00:00:00 2001 From: Niyas Sait Date: Mon, 11 Apr 2022 16:30:51 +0100 Subject: VS: Add support for enumerating VS instances with vswhere --- Source/cmVSSetupHelper.cxx | 58 ++++++++++++++++++++++++++++++++++++++++++++-- Source/cmVSSetupHelper.h | 2 ++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx index 49ad441..1a3e72e 100644 --- a/Source/cmVSSetupHelper.cxx +++ b/Source/cmVSSetupHelper.cxx @@ -4,6 +4,11 @@ #include +#if !defined(CMAKE_BOOTSTRAP) +# include +# include +#endif + #include "cmsys/Encoding.hxx" #include "cmsys/FStream.hxx" @@ -295,6 +300,54 @@ bool cmVSSetupAPIHelper::IsEWDKEnabled() return false; } +bool cmVSSetupAPIHelper::EnumerateVSInstancesWithVswhere( + std::vector& VSInstances) +{ +#if !defined(CMAKE_BOOTSTRAP) + // Construct vswhere command to get installed VS instances in JSON format + std::string vswhereExe = getenv("ProgramFiles(x86)") + + std::string(R"(\Microsoft Visual Studio\Installer\vswhere.exe)"); + std::vector vswhereCmd = { vswhereExe, "-format", "json" }; + + // Execute vswhere command and capture JSON output + std::string json_output; + int retVal = 1; + if (!cmSystemTools::RunSingleCommand(vswhereCmd, &json_output, &json_output, + &retVal, nullptr, + cmSystemTools::OUTPUT_NONE)) { + return false; + } + + // Parse JSON output and iterate over elements + Json::CharReaderBuilder builder; + auto jsonReader = std::unique_ptr(builder.newCharReader()); + Json::Value json; + std::string error; + + if (!jsonReader->parse(json_output.data(), + json_output.data() + json_output.size(), &json, + &error)) { + return false; + } + + for (const auto& item : json) { + VSInstanceInfo instance; + instance.Version = item["installationVersion"].asString(); + instance.VSInstallLocation = item["installationPath"].asString(); + instance.IsWin10SDKInstalled = true; + instance.IsWin81SDKInstalled = false; + cmSystemTools::ConvertToUnixSlashes(instance.VSInstallLocation); + if (LoadVSInstanceVCToolsetVersion(instance)) { + VSInstances.push_back(instance); + } + } + return true; +#else + static_cast(VSInstances); + return false; +#endif +} + bool cmVSSetupAPIHelper::EnumerateVSInstancesWithCOM( std::vector& VSInstances) { @@ -371,8 +424,9 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() std::vector vecVSInstancesAll; - // Enumerate VS instances with COM interface - if (!EnumerateVSInstancesWithCOM(vecVSInstancesAll)) { + // Enumerate VS instances with either COM interface or Vswhere + if (!EnumerateVSInstancesWithCOM(vecVSInstancesAll) && + !EnumerateVSInstancesWithVswhere(vecVSInstancesAll)) { return false; } diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h index e7a276e..a16f00b 100644 --- a/Source/cmVSSetupHelper.h +++ b/Source/cmVSSetupHelper.h @@ -118,6 +118,8 @@ private: int ChooseVSInstance(const std::vector& vecVSInstances); bool EnumerateAndChooseVSInstance(); bool LoadSpecifiedVSInstanceFromDisk(); + bool EnumerateVSInstancesWithVswhere( + std::vector& VSInstances); bool EnumerateVSInstancesWithCOM(std::vector& VSInstances); unsigned int Version; -- cgit v0.12