Răsfoiți Sursa

Merge topic 'vswhere-support'

f85913fa08 VS: Add support for enumerating VS instances with vswhere
069cff63f6 VS: refactor EnumerateAndChooseVSInstance

Acked-by: Kitware Robot <[email protected]>
Merge-request: !7159
Brad King 3 ani în urmă
părinte
comite
3eb9f69ffe
2 a modificat fișierele cu 129 adăugiri și 56 ștergeri
  1. 126 56
      Source/cmVSSetupHelper.cxx
  2. 3 0
      Source/cmVSSetupHelper.h

+ 126 - 56
Source/cmVSSetupHelper.cxx

@@ -4,6 +4,11 @@
 
 #include <utility>
 
+#if !defined(CMAKE_BOOTSTRAP)
+#  include <cm3p/json/reader.h>
+#  include <cm3p/json/value.h>
+#endif
+
 #include "cmsys/Encoding.hxx"
 #include "cmsys/FStream.hxx"
 
@@ -295,6 +300,87 @@ bool cmVSSetupAPIHelper::IsEWDKEnabled()
   return false;
 }
 
+bool cmVSSetupAPIHelper::EnumerateVSInstancesWithVswhere(
+  std::vector<VSInstanceInfo>& 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<std::string> 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<Json::CharReader>(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<void>(VSInstances);
+  return false;
+#endif
+}
+
+bool cmVSSetupAPIHelper::EnumerateVSInstancesWithCOM(
+  std::vector<VSInstanceInfo>& VSInstances)
+{
+  if (initializationFailure || setupConfig == NULL || setupConfig2 == NULL ||
+      setupHelper == NULL)
+    return false;
+
+  SmartCOMPtr<IEnumSetupInstances> enumInstances = NULL;
+  if (FAILED(
+        setupConfig2->EnumInstances((IEnumSetupInstances**)&enumInstances)) ||
+      !enumInstances) {
+    return false;
+  }
+
+  SmartCOMPtr<ISetupInstance> instance;
+  while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) {
+    SmartCOMPtr<ISetupInstance2> 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 +407,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 +416,60 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance()
     cmSystemTools::ConvertToUnixSlashes(envVSCommonToolsDir);
   }
 
-  std::vector<VSInstanceInfo> vecVSInstances;
-  SmartCOMPtr<IEnumSetupInstances> enumInstances = NULL;
-  if (FAILED(
-        setupConfig2->EnumInstances((IEnumSetupInstances**)&enumInstances)) ||
-      !enumInstances) {
-    return false;
-  }
-
   std::string const wantVersion = std::to_string(this->Version) + '.';
 
   bool specifiedLocationNotSpecifiedVersion = false;
 
   SmartCOMPtr<ISetupInstance> instance;
-  while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) {
-    SmartCOMPtr<ISetupInstance2> instance2 = NULL;
-    if (FAILED(
-          instance->QueryInterface(IID_ISetupInstance2, (void**)&instance2)) ||
-        !instance2) {
-      instance = NULL;
+
+  std::vector<VSInstanceInfo> vecVSInstancesAll;
+
+  // Enumerate VS instances with either COM interface or Vswhere
+  if (!EnumerateVSInstancesWithCOM(vecVSInstancesAll) &&
+      !EnumerateVSInstancesWithVswhere(vecVSInstancesAll)) {
+    return false;
+  }
+
+  std::vector<VSInstanceInfo> 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);
     }
   }
 

+ 3 - 0
Source/cmVSSetupHelper.h

@@ -118,6 +118,9 @@ private:
   int ChooseVSInstance(const std::vector<VSInstanceInfo>& vecVSInstances);
   bool EnumerateAndChooseVSInstance();
   bool LoadSpecifiedVSInstanceFromDisk();
+  bool EnumerateVSInstancesWithVswhere(
+    std::vector<VSInstanceInfo>& VSInstances);
+  bool EnumerateVSInstancesWithCOM(std::vector<VSInstanceInfo>& VSInstances);
 
   unsigned int Version;