From 083cf7e8a2515d9f838f3edbb2724fd3b17d83cd Mon Sep 17 00:00:00 2001
From: Eicke Herbertz <wolletd@posteo.de>
Date: Fri, 12 Apr 2019 00:16:46 +0200
Subject: cmake: Allow default generator to be set by environment variables

When there is no Generator available in the Cache, this will read
CMAKE_GENERATOR from environment before using the CMake platform default.
If CMAKE_GENERATOR is empty, use the platform default.

If a environment default generator is specified, subsequent variables
CMAKE_GENERATOR_(INSTANCE,PLATFORM,TOOLSET) are also evaluated
in the same way.
---
 Source/cmake.cxx | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 Source/cmake.h   | 10 +++++++++
 2 files changed, 71 insertions(+), 6 deletions(-)

diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index fc24ac0..c861f3b 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -159,6 +159,9 @@ cmake::cmake(Role role, cmState::Mode mode)
 #endif
 
   this->GlobalGenerator = nullptr;
+  this->GeneratorInstanceSet = false;
+  this->GeneratorPlatformSet = false;
+  this->GeneratorToolsetSet = false;
   this->CurrentWorkingMode = NORMAL_MODE;
 
 #ifdef CMAKE_BUILD_WITH_CMAKE
@@ -174,6 +177,10 @@ cmake::cmake(Role role, cmState::Mode mode)
     this->AddProjectCommands();
   }
 
+  if (mode == cmState::Project) {
+    this->LoadEnvironmentPresets();
+  }
+
   // Make sure we can capture the build tool output.
   cmSystemTools::EnableVSConsoleOutput();
 
@@ -612,6 +619,35 @@ bool cmake::FindPackage(const std::vector<std::string>& args)
   return packageFound;
 }
 
+void cmake::LoadEnvironmentPresets()
+{
+  std::string envGenVar;
+  bool hasEnvironmentGenerator = false;
+  if (cmSystemTools::GetEnv("CMAKE_GENERATOR", envGenVar)) {
+    hasEnvironmentGenerator = true;
+    this->EnvironmentGenerator = envGenVar;
+  }
+
+  auto readGeneratorVar = [&](std::string name, std::string& key) {
+    std::string varValue;
+    if (cmSystemTools::GetEnv(name, varValue)) {
+      if (hasEnvironmentGenerator) {
+        key = varValue;
+      } else if (!this->GetIsInTryCompile()) {
+        std::string message = "Warning: Environment variable ";
+        message += name;
+        message += " will be ignored, because CMAKE_GENERATOR ";
+        message += "is not set.";
+        cmSystemTools::Message(message, "Warning");
+      }
+    }
+  };
+
+  readGeneratorVar("CMAKE_GENERATOR_INSTANCE", this->GeneratorInstance);
+  readGeneratorVar("CMAKE_GENERATOR_PLATFORM", this->GeneratorPlatform);
+  readGeneratorVar("CMAKE_GENERATOR_TOOLSET", this->GeneratorToolset);
+}
+
 // Parse the args
 void cmake::SetArgs(const std::vector<std::string>& args)
 {
@@ -759,7 +795,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
         cmSystemTools::Error("Multiple -A options not allowed");
         return;
       }
-      this->GeneratorPlatform = value;
+      this->SetGeneratorPlatform(value);
       havePlatform = true;
     } else if (arg.find("-T", 0) == 0) {
       std::string value = arg.substr(2);
@@ -775,7 +811,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
         cmSystemTools::Error("Multiple -T options not allowed");
         return;
       }
-      this->GeneratorToolset = value;
+      this->SetGeneratorToolset(value);
       haveToolset = true;
     } else if (arg.find("-G", 0) == 0) {
       std::string value = arg.substr(2);
@@ -806,6 +842,16 @@ void cmake::SetArgs(const std::vector<std::string>& args)
     else {
       this->SetDirectoriesFromFile(arg.c_str());
     }
+    // Empty instance, platform and toolset if only a generator is specified
+    if (this->GlobalGenerator) {
+      this->GeneratorInstance = "";
+      if (!this->GeneratorPlatformSet) {
+        this->GeneratorPlatform = "";
+      }
+      if (!this->GeneratorToolsetSet) {
+        this->GeneratorToolset = "";
+      }
+    }
   }
 
   const bool haveSourceDir = !this->GetHomeDirectory().empty();
@@ -1419,8 +1465,7 @@ int cmake::ActualConfigure()
 
   if (const std::string* instance =
         this->State->GetInitializedCacheValue("CMAKE_GENERATOR_INSTANCE")) {
-    if (!this->GeneratorInstance.empty() &&
-        this->GeneratorInstance != *instance) {
+    if (this->GeneratorInstanceSet && this->GeneratorInstance != *instance) {
       std::string message = "Error: generator instance: ";
       message += this->GeneratorInstance;
       message += "\nDoes not match the instance used previously: ";
@@ -1438,7 +1483,7 @@ int cmake::ActualConfigure()
 
   if (const std::string* platformName =
         this->State->GetInitializedCacheValue("CMAKE_GENERATOR_PLATFORM")) {
-    if (!this->GeneratorPlatform.empty() &&
+    if (this->GeneratorPlatformSet &&
         this->GeneratorPlatform != *platformName) {
       std::string message = "Error: generator platform: ";
       message += this->GeneratorPlatform;
@@ -1457,7 +1502,7 @@ int cmake::ActualConfigure()
 
   if (const std::string* tsName =
         this->State->GetInitializedCacheValue("CMAKE_GENERATOR_TOOLSET")) {
-    if (!this->GeneratorToolset.empty() && this->GeneratorToolset != *tsName) {
+    if (this->GeneratorToolsetSet && this->GeneratorToolset != *tsName) {
       std::string message = "Error: generator toolset: ";
       message += this->GeneratorToolset;
       message += "\nDoes not match the toolset used previously: ";
@@ -1535,6 +1580,16 @@ int cmake::ActualConfigure()
 
 std::unique_ptr<cmGlobalGenerator> cmake::EvaluateDefaultGlobalGenerator()
 {
+  if (!this->EnvironmentGenerator.empty()) {
+    cmGlobalGenerator* gen =
+      this->CreateGlobalGenerator(this->EnvironmentGenerator);
+    if (!gen) {
+      cmSystemTools::Error("CMAKE_GENERATOR was set but the specified "
+                           "generator doesn't exist. Using CMake default.");
+    } else {
+      return std::unique_ptr<cmGlobalGenerator>(gen);
+    }
+  }
 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
   std::string found;
   // Try to find the newest VS installed on the computer and
diff --git a/Source/cmake.h b/Source/cmake.h
index 8b4b396..beec11d 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -201,18 +201,21 @@ public:
   void SetGeneratorInstance(std::string const& instance)
   {
     this->GeneratorInstance = instance;
+    this->GeneratorInstanceSet = true;
   }
 
   //! Set the name of the selected generator-specific platform.
   void SetGeneratorPlatform(std::string const& ts)
   {
     this->GeneratorPlatform = ts;
+    this->GeneratorPlatformSet = true;
   }
 
   //! Set the name of the selected generator-specific toolset.
   void SetGeneratorToolset(std::string const& ts)
   {
     this->GeneratorToolset = ts;
+    this->GeneratorToolsetSet = true;
   }
 
   const std::vector<std::string>& GetSourceExtensions() const
@@ -263,6 +266,9 @@ public:
    */
   int GetSystemInformation(std::vector<std::string>&);
 
+  //! Parse environment variables
+  void LoadEnvironmentPresets();
+
   //! Parse command line arguments
   void SetArgs(const std::vector<std::string>& args);
 
@@ -461,6 +467,9 @@ protected:
   std::string GeneratorInstance;
   std::string GeneratorPlatform;
   std::string GeneratorToolset;
+  bool GeneratorInstanceSet;
+  bool GeneratorPlatformSet;
+  bool GeneratorToolsetSet;
 
   //! read in a cmake list file to initialize the cache
   void ReadListFile(const std::vector<std::string>& args,
@@ -503,6 +512,7 @@ private:
   std::string CheckStampFile;
   std::string CheckStampList;
   std::string VSSolutionFile;
+  std::string EnvironmentGenerator;
   std::vector<std::string> SourceFileExtensions;
   std::unordered_set<std::string> SourceFileExtensionsSet;
   std::vector<std::string> HeaderFileExtensions;
-- 
cgit v0.12


From a48ce8f4bf0677e9e8d054892836e8a980ffa435 Mon Sep 17 00:00:00 2001
From: Eicke Herbertz <wolletd@posteo.de>
Date: Fri, 12 Apr 2019 00:50:33 +0200
Subject: Help: Add documentation for default generator environment variables

Documentation for environment variables that control the default
generator selection:

* CMAKE_GENERATOR
* CMAKE_GENERATOR_INSTANCE
* CMAKE_GENERATOR_PLATFORM
* CMAKE_GENERATOR_TOOLSET
---
 Help/envvar/CMAKE_GENERATOR.rst            | 16 ++++++++++++++++
 Help/envvar/CMAKE_GENERATOR_INSTANCE.rst   |  7 +++++++
 Help/envvar/CMAKE_GENERATOR_PLATFORM.rst   |  8 ++++++++
 Help/envvar/CMAKE_GENERATOR_TOOLSET.rst    |  8 ++++++++
 Help/manual/OPTIONS_BUILD.txt              |  3 +++
 Help/manual/cmake-env-variables.7.rst      |  4 ++++
 Help/release/dev/default-generator-env.rst |  9 +++++++++
 Help/variable/CMAKE_GENERATOR.rst          |  5 +++++
 Help/variable/CMAKE_GENERATOR_INSTANCE.rst |  7 ++++---
 Help/variable/CMAKE_GENERATOR_PLATFORM.rst |  3 ++-
 Help/variable/CMAKE_GENERATOR_TOOLSET.rst  |  3 ++-
 11 files changed, 68 insertions(+), 5 deletions(-)
 create mode 100644 Help/envvar/CMAKE_GENERATOR.rst
 create mode 100644 Help/envvar/CMAKE_GENERATOR_INSTANCE.rst
 create mode 100644 Help/envvar/CMAKE_GENERATOR_PLATFORM.rst
 create mode 100644 Help/envvar/CMAKE_GENERATOR_TOOLSET.rst
 create mode 100644 Help/release/dev/default-generator-env.rst

diff --git a/Help/envvar/CMAKE_GENERATOR.rst b/Help/envvar/CMAKE_GENERATOR.rst
new file mode 100644
index 0000000..f2d055f
--- /dev/null
+++ b/Help/envvar/CMAKE_GENERATOR.rst
@@ -0,0 +1,16 @@
+CMAKE_GENERATOR
+---------------
+
+.. include:: ENV_VAR.txt
+
+Specifies the CMake default generator to use when no generator is supplied
+with ``-G``. If the provided value doesn't name a generator known by CMake,
+the internal default is used.  Either way the resulting generator selection
+is stored in the :variable:`CMAKE_GENERATOR` variable.
+
+Some generators may be additionally configured using the environment
+variables:
+
+* :envvar:`CMAKE_GENERATOR_PLATFORM`
+* :envvar:`CMAKE_GENERATOR_TOOLSET`
+* :envvar:`CMAKE_GENERATOR_INSTANCE`
diff --git a/Help/envvar/CMAKE_GENERATOR_INSTANCE.rst b/Help/envvar/CMAKE_GENERATOR_INSTANCE.rst
new file mode 100644
index 0000000..1654fa1
--- /dev/null
+++ b/Help/envvar/CMAKE_GENERATOR_INSTANCE.rst
@@ -0,0 +1,7 @@
+CMAKE_GENERATOR_INSTANCE
+------------------------
+
+.. include:: ENV_VAR.txt
+
+Default value for :variable:`CMAKE_GENERATOR_INSTANCE` if no Cache entry is
+present. This value is only applied if :envvar:`CMAKE_GENERATOR` is set.
diff --git a/Help/envvar/CMAKE_GENERATOR_PLATFORM.rst b/Help/envvar/CMAKE_GENERATOR_PLATFORM.rst
new file mode 100644
index 0000000..917b30b
--- /dev/null
+++ b/Help/envvar/CMAKE_GENERATOR_PLATFORM.rst
@@ -0,0 +1,8 @@
+CMAKE_GENERATOR_PLATFORM
+------------------------
+
+.. include:: ENV_VAR.txt
+
+Default value for :variable:`CMAKE_GENERATOR_PLATFORM` if no Cache entry
+is present and no value is specified by :manual:`cmake(1)` ``-A`` option.
+This value is only applied if :envvar:`CMAKE_GENERATOR` is set.
diff --git a/Help/envvar/CMAKE_GENERATOR_TOOLSET.rst b/Help/envvar/CMAKE_GENERATOR_TOOLSET.rst
new file mode 100644
index 0000000..7ac3856
--- /dev/null
+++ b/Help/envvar/CMAKE_GENERATOR_TOOLSET.rst
@@ -0,0 +1,8 @@
+CMAKE_GENERATOR_TOOLSET
+-----------------------
+
+.. include:: ENV_VAR.txt
+
+Default value for :variable:`CMAKE_GENERATOR_TOOLSET` if no Cache entry
+is present and no value is specified by :manual:`cmake(1)` ``-T`` option.
+This value is only applied if :envvar:`CMAKE_GENERATOR` is set.
diff --git a/Help/manual/OPTIONS_BUILD.txt b/Help/manual/OPTIONS_BUILD.txt
index 64fd816..810aaa9 100644
--- a/Help/manual/OPTIONS_BUILD.txt
+++ b/Help/manual/OPTIONS_BUILD.txt
@@ -56,6 +56,9 @@
  build system.  Possible generator names are specified in the
  :manual:`cmake-generators(7)` manual.
 
+ If not specified, CMake checks the :envvar:`CMAKE_GENERATOR` environment
+ variable and otherwise falls back to a builtin default selection.
+
 ``-T <toolset-spec>``
  Toolset specification for the generator, if supported.
 
diff --git a/Help/manual/cmake-env-variables.7.rst b/Help/manual/cmake-env-variables.7.rst
index c433412..89c9119 100644
--- a/Help/manual/cmake-env-variables.7.rst
+++ b/Help/manual/cmake-env-variables.7.rst
@@ -23,6 +23,10 @@ Environment Variables that Control the Build
 
    /envvar/CMAKE_BUILD_PARALLEL_LEVEL
    /envvar/CMAKE_CONFIG_TYPE
+   /envvar/CMAKE_GENERATOR
+   /envvar/CMAKE_GENERATOR_INSTANCE
+   /envvar/CMAKE_GENERATOR_PLATFORM
+   /envvar/CMAKE_GENERATOR_TOOLSET
    /envvar/CMAKE_MSVCIDE_RUN_PATH
    /envvar/CMAKE_NO_VERBOSE
    /envvar/CMAKE_OSX_ARCHITECTURES
diff --git a/Help/release/dev/default-generator-env.rst b/Help/release/dev/default-generator-env.rst
new file mode 100644
index 0000000..3f20475
--- /dev/null
+++ b/Help/release/dev/default-generator-env.rst
@@ -0,0 +1,9 @@
+default-generator-env
+---------------------
+
+* The :envvar:`CMAKE_GENERATOR` environment variable was added
+  to specify a default generator to use when :manual:`cmake(1)` is
+  run without a ``-G`` option.  Additionally, environment variables
+  :envvar:`CMAKE_GENERATOR_PLATFORM`, :envvar:`CMAKE_GENERATOR_TOOLSET`,
+  and :envvar:`CMAKE_GENERATOR_INSTANCE` were created to configure
+  the generator.
diff --git a/Help/variable/CMAKE_GENERATOR.rst b/Help/variable/CMAKE_GENERATOR.rst
index cce04c1..ec52cd4 100644
--- a/Help/variable/CMAKE_GENERATOR.rst
+++ b/Help/variable/CMAKE_GENERATOR.rst
@@ -5,3 +5,8 @@ The generator used to build the project.  See :manual:`cmake-generators(7)`.
 
 The name of the generator that is being used to generate the build
 files.  (e.g.  ``Unix Makefiles``, ``Ninja``, etc.)
+
+The value of this variable should never be modified by project code.
+A generator may be selected via the :manual:`cmake(1)` ``-G`` option,
+interactively in :manual:`cmake-gui(1)`, or via the :envvar:`CMAKE_GENERATOR`
+environment variable.
diff --git a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst
index 78c81b1..3657ed4 100644
--- a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst
+++ b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst
@@ -5,9 +5,10 @@ Generator-specific instance specification provided by user.
 
 Some CMake generators support selection of an instance of the native build
 system when multiple instances are available.  If the user specifies an
-instance (e.g. by setting this cache entry), or after a default instance is
-chosen when a build tree is first configured, the value will be available in
-this variable.
+instance (e.g. by setting this cache entry or via the
+:envvar:`CMAKE_GENERATOR_INSTANCE` environment variable), or after a default
+instance is chosen when a build tree is first configured, the value will be
+available in this variable.
 
 The value of this variable should never be modified by project code.
 A toolchain file specified by the :variable:`CMAKE_TOOLCHAIN_FILE`
diff --git a/Help/variable/CMAKE_GENERATOR_PLATFORM.rst b/Help/variable/CMAKE_GENERATOR_PLATFORM.rst
index 963f0a4..2c115a3 100644
--- a/Help/variable/CMAKE_GENERATOR_PLATFORM.rst
+++ b/Help/variable/CMAKE_GENERATOR_PLATFORM.rst
@@ -6,7 +6,8 @@ Generator-specific target platform specification provided by user.
 Some CMake generators support a target platform name to be given
 to the native build system to choose a compiler toolchain.
 If the user specifies a platform name (e.g. via the :manual:`cmake(1)` ``-A``
-option) the value will be available in this variable.
+option or via the :envvar:`CMAKE_GENERATOR_PLATFORM` environment variable)
+the value will be available in this variable.
 
 The value of this variable should never be modified by project code.
 A toolchain file specified by the :variable:`CMAKE_TOOLCHAIN_FILE`
diff --git a/Help/variable/CMAKE_GENERATOR_TOOLSET.rst b/Help/variable/CMAKE_GENERATOR_TOOLSET.rst
index e77f211..a01a8b7 100644
--- a/Help/variable/CMAKE_GENERATOR_TOOLSET.rst
+++ b/Help/variable/CMAKE_GENERATOR_TOOLSET.rst
@@ -5,7 +5,8 @@ Native build system toolset specification provided by user.
 
 Some CMake generators support a toolset specification to tell the
 native build system how to choose a compiler.  If the user specifies
-a toolset (e.g.  via the :manual:`cmake(1)` ``-T`` option) the value
+a toolset (e.g. via the :manual:`cmake(1)` ``-T`` option or via
+the :envvar:`CMAKE_GENERATOR_TOOLSET` environment variable) the value
 will be available in this variable.
 
 The value of this variable should never be modified by project code.
-- 
cgit v0.12


From d0f0ba0f7a39e70fbed197e717292b74150cf84f Mon Sep 17 00:00:00 2001
From: Eicke Herbertz <wolletd@posteo.de>
Date: Sat, 4 May 2019 23:54:58 +0200
Subject: Tests: Add environment generator tests

---
 Tests/EnforceConfig.cmake.in                       |  6 ++
 .../CommandLine/EnvGenerator/CMakeLists.txt        | 10 ++++
 .../CommandLine/Envgen-A-platform-result.txt       |  1 +
 .../CommandLine/Envgen-A-platform-stderr-vs9.txt   |  2 +
 .../CommandLine/Envgen-A-platform-stderr.txt       |  2 +
 .../Envgen-G-implicit-platform-stdout.txt          |  1 +
 .../CommandLine/Envgen-T-toolset-result.txt        |  1 +
 .../CommandLine/Envgen-T-toolset-stderr.txt        |  2 +
 Tests/RunCMake/CommandLine/Envgen-bad-result.txt   |  1 +
 Tests/RunCMake/CommandLine/Envgen-bad-stderr.txt   |  5 ++
 .../CommandLine/Envgen-instance-invalid-result.txt |  1 +
 .../CommandLine/Envgen-instance-invalid-stderr.txt |  2 +
 Tests/RunCMake/CommandLine/Envgen-ninja-result.txt |  1 +
 Tests/RunCMake/CommandLine/Envgen-ninja-stderr.txt |  4 ++
 .../CommandLine/Envgen-platform-invalid-result.txt |  1 +
 .../Envgen-platform-invalid-stderr-vs9.txt         |  2 +
 .../CommandLine/Envgen-platform-invalid-stderr.txt |  2 +
 .../CommandLine/Envgen-toolset-invalid-result.txt  |  1 +
 .../CommandLine/Envgen-toolset-invalid-stderr.txt  |  2 +
 Tests/RunCMake/CommandLine/Envgen-unset-result.txt |  1 +
 Tests/RunCMake/CommandLine/Envgen-unset-stderr.txt |  4 ++
 .../CommandLine/Envgen-warnings-result.txt         |  1 +
 .../CommandLine/Envgen-warnings-stderr.txt         |  7 +++
 Tests/RunCMake/CommandLine/RunCMakeTest.cmake      | 68 ++++++++++++++++++++++
 24 files changed, 128 insertions(+)
 create mode 100644 Tests/RunCMake/CommandLine/EnvGenerator/CMakeLists.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-A-platform-result.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-A-platform-stderr-vs9.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-A-platform-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-G-implicit-platform-stdout.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-T-toolset-result.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-T-toolset-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-bad-result.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-bad-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-instance-invalid-result.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-instance-invalid-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-ninja-result.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-ninja-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-platform-invalid-result.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr-vs9.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-toolset-invalid-result.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-toolset-invalid-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-unset-result.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-unset-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-warnings-result.txt
 create mode 100644 Tests/RunCMake/CommandLine/Envgen-warnings-stderr.txt

diff --git a/Tests/EnforceConfig.cmake.in b/Tests/EnforceConfig.cmake.in
index 8c0817c..f84d180 100644
--- a/Tests/EnforceConfig.cmake.in
+++ b/Tests/EnforceConfig.cmake.in
@@ -23,4 +23,10 @@ if(NOT CTEST_CONFIGURATION_TYPE)
   message("Guessing configuration ${CTEST_CONFIGURATION_TYPE}")
 endif()
 
+# Isolate tests from user configuration in the environment.
+unset(ENV{CMAKE_GENERATOR})
+unset(ENV{CMAKE_GENERATOR_INSTANCE})
+unset(ENV{CMAKE_GENERATOR_PLATFORM})
+unset(ENV{CMAKE_GENERATOR_TOOLSET})
+
 @TEST_HOME_ENV_CODE@
diff --git a/Tests/RunCMake/CommandLine/EnvGenerator/CMakeLists.txt b/Tests/RunCMake/CommandLine/EnvGenerator/CMakeLists.txt
new file mode 100644
index 0000000..2b8c65c
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/EnvGenerator/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.14)
+project(EnvGenerator C)
+if(CMAKE_GENERATOR MATCHES "Visual Studio")
+  message(STATUS "CMAKE_VS_PLATFORM_NAME='${CMAKE_VS_PLATFORM_NAME}'")
+endif()
+add_custom_command(
+  OUTPUT output.txt
+  COMMAND ${CMAKE_COMMAND} -E echo CustomCommand > output.txt
+  )
+add_custom_target(CustomTarget ALL DEPENDS output.txt)
diff --git a/Tests/RunCMake/CommandLine/Envgen-A-platform-result.txt b/Tests/RunCMake/CommandLine/Envgen-A-platform-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-A-platform-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-A-platform-stderr-vs9.txt b/Tests/RunCMake/CommandLine/Envgen-A-platform-stderr-vs9.txt
new file mode 100644
index 0000000..4eae6aa
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-A-platform-stderr-vs9.txt
@@ -0,0 +1,2 @@
+^CMake Error at CMakeLists.+
+  No CMAKE_C_COMPILER could be found.
diff --git a/Tests/RunCMake/CommandLine/Envgen-A-platform-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-A-platform-stderr.txt
new file mode 100644
index 0000000..09c2d2b
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-A-platform-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error at CMakeLists.+
+.+Platform='fromcli'.+
diff --git a/Tests/RunCMake/CommandLine/Envgen-G-implicit-platform-stdout.txt b/Tests/RunCMake/CommandLine/Envgen-G-implicit-platform-stdout.txt
new file mode 100644
index 0000000..4dd6be1
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-G-implicit-platform-stdout.txt
@@ -0,0 +1 @@
+-- CMAKE_VS_PLATFORM_NAME='(x64|Win32)'
diff --git a/Tests/RunCMake/CommandLine/Envgen-T-toolset-result.txt b/Tests/RunCMake/CommandLine/Envgen-T-toolset-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-T-toolset-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-T-toolset-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-T-toolset-stderr.txt
new file mode 100644
index 0000000..b432c19
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-T-toolset-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error at CMakeLists.+
+.+(Platform Toolset = 'fromcli'|Specified platform toolset \(fromcli\) is not installed or invalid).+
diff --git a/Tests/RunCMake/CommandLine/Envgen-bad-result.txt b/Tests/RunCMake/CommandLine/Envgen-bad-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-bad-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-bad-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-bad-stderr.txt
new file mode 100644
index 0000000..4a1215e
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-bad-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error: No generator specified for -G
+CMake Error: CMAKE_GENERATOR was set but the specified generator doesn't exist. Using CMake default.
+
+Generators.*
+\* (Unix Makefiles|Visual Studio).*
diff --git a/Tests/RunCMake/CommandLine/Envgen-instance-invalid-result.txt b/Tests/RunCMake/CommandLine/Envgen-instance-invalid-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-instance-invalid-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-instance-invalid-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-instance-invalid-stderr.txt
new file mode 100644
index 0000000..d53daa5
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-instance-invalid-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error at CMakeLists.+
+  could not find specified instance of Visual Studio.+
diff --git a/Tests/RunCMake/CommandLine/Envgen-ninja-result.txt b/Tests/RunCMake/CommandLine/Envgen-ninja-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-ninja-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-ninja-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-ninja-stderr.txt
new file mode 100644
index 0000000..0d455db
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-ninja-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error: No generator specified for -G
+
+Generators.*
+\* Ninja.*
diff --git a/Tests/RunCMake/CommandLine/Envgen-platform-invalid-result.txt b/Tests/RunCMake/CommandLine/Envgen-platform-invalid-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-platform-invalid-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr-vs9.txt b/Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr-vs9.txt
new file mode 100644
index 0000000..4eae6aa
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr-vs9.txt
@@ -0,0 +1,2 @@
+^CMake Error at CMakeLists.+
+  No CMAKE_C_COMPILER could be found.
diff --git a/Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr.txt
new file mode 100644
index 0000000..76a8f1c
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-platform-invalid-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error at CMakeLists.+
+.+Platform='invalid'.+
diff --git a/Tests/RunCMake/CommandLine/Envgen-toolset-invalid-result.txt b/Tests/RunCMake/CommandLine/Envgen-toolset-invalid-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-toolset-invalid-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-toolset-invalid-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-toolset-invalid-stderr.txt
new file mode 100644
index 0000000..51fce60
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-toolset-invalid-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error at CMakeLists.+
+.+(Platform Toolset = 'invalid'|Specified platform toolset \(invalid\) is not installed or invalid).+
diff --git a/Tests/RunCMake/CommandLine/Envgen-unset-result.txt b/Tests/RunCMake/CommandLine/Envgen-unset-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-unset-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-unset-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-unset-stderr.txt
new file mode 100644
index 0000000..ec6ec92
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-unset-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error: No generator specified for -G
+
+Generators.*
+\* (Unix Makefiles|Visual Studio).*
diff --git a/Tests/RunCMake/CommandLine/Envgen-warnings-result.txt b/Tests/RunCMake/CommandLine/Envgen-warnings-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-warnings-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/Envgen-warnings-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-warnings-stderr.txt
new file mode 100644
index 0000000..47f9c9e
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-warnings-stderr.txt
@@ -0,0 +1,7 @@
+^Warning: Environment variable CMAKE_GENERATOR_INSTANCE will be ignored, because CMAKE_GENERATOR is not set.
+Warning: Environment variable CMAKE_GENERATOR_PLATFORM will be ignored, because CMAKE_GENERATOR is not set.
+Warning: Environment variable CMAKE_GENERATOR_TOOLSET will be ignored, because CMAKE_GENERATOR is not set.
+CMake Error: No generator specified for -G
+
+Generators.*
+\* (Unix Makefiles|Visual Studio).*
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index ea749ea..dd1180b 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -164,6 +164,74 @@ function(run_BuildDir)
 endfunction()
 run_BuildDir()
 
+function(run_EnvironmentGenerator)
+  set(source_dir ${RunCMake_SOURCE_DIR}/EnvGenerator)
+
+  set(ENV{CMAKE_GENERATOR_INSTANCE} "instance")
+  set(ENV{CMAKE_GENERATOR_PLATFORM} "platform")
+  set(ENV{CMAKE_GENERATOR_TOOLSET} "toolset")
+  run_cmake_command(Envgen-warnings ${CMAKE_COMMAND} -G)
+  unset(ENV{CMAKE_GENERATOR_INSTANCE})
+  unset(ENV{CMAKE_GENERATOR_PLATFORM})
+  unset(ENV{CMAKE_GENERATOR_TOOLSET})
+
+  # Test CMAKE_GENERATOR without actual configuring
+  run_cmake_command(Envgen-unset ${CMAKE_COMMAND} -G)
+  set(ENV{CMAKE_GENERATOR} "Ninja")
+  run_cmake_command(Envgen-ninja ${CMAKE_COMMAND} -G)
+  set(ENV{CMAKE_GENERATOR} "NoSuchGenerator")
+  run_cmake_command(Envgen-bad ${CMAKE_COMMAND} -G)
+  unset(ENV{CMAKE_GENERATOR})
+
+  if(RunCMake_GENERATOR MATCHES "Visual Studio.*")
+    set(ENV{CMAKE_GENERATOR} "${RunCMake_GENERATOR}")
+    run_cmake_command(Envgen ${CMAKE_COMMAND} ${source_dir})
+    # Toolset is available since VS 2010.
+    if(RunCMake_GENERATOR MATCHES "Visual Studio [1-9][0-9]")
+      set(ENV{CMAKE_GENERATOR_TOOLSET} "invalid")
+      # Envvar shouldn't affect existing build tree
+      run_cmake_command(Envgen-toolset-existing ${CMAKE_COMMAND} -E chdir ..
+        ${CMAKE_COMMAND} --build Envgen-build)
+      run_cmake_command(Envgen-toolset-invalid ${CMAKE_COMMAND} ${source_dir})
+      # Command line -G implies -T""
+      run_cmake_command(Envgen-G-implicit-toolset ${CMAKE_COMMAND} -G "${RunCMake_GENERATOR}" ${source_dir})
+      run_cmake_command(Envgen-T-toolset ${CMAKE_COMMAND} -T "fromcli" ${source_dir})
+      unset(ENV{CMAKE_GENERATOR_TOOLSET})
+    endif()
+    # Platform can be set only if not in generator name.
+    if(RunCMake_GENERATOR MATCHES "^Visual Studio [0-9]+ [0-9]+$")
+      set(ENV{CMAKE_GENERATOR_PLATFORM} "invalid")
+      # Envvar shouldn't affect existing build tree
+      run_cmake_command(Envgen-platform-existing ${CMAKE_COMMAND} -E chdir ..
+        ${CMAKE_COMMAND} --build Envgen-build)
+      if(RunCMake_GENERATOR MATCHES "^Visual Studio 9 ")
+        set(RunCMake-stderr-file "Envgen-platform-invalid-stderr-vs9.txt")
+      endif()
+      run_cmake_command(Envgen-platform-invalid ${CMAKE_COMMAND} ${source_dir})
+      unset(RunCMake-stderr-file)
+      # Command line -G implies -A""
+      run_cmake_command(Envgen-G-implicit-platform ${CMAKE_COMMAND} -G "${RunCMake_GENERATOR}" ${source_dir})
+      if(RunCMake_GENERATOR MATCHES "^Visual Studio 9 ")
+        set(RunCMake-stderr-file "Envgen-A-platform-stderr-vs9.txt")
+      endif()
+      run_cmake_command(Envgen-A-platform ${CMAKE_COMMAND} -A "fromcli" ${source_dir})
+      unset(RunCMake-stderr-file)
+      unset(ENV{CMAKE_GENERATOR_PLATFORM})
+    endif()
+    # Instance is available since VS 2017.
+    if(RunCMake_GENERATOR MATCHES "Visual Studio (15|16).*")
+      set(ENV{CMAKE_GENERATOR_INSTANCE} "invalid")
+      # Envvar shouldn't affect existing build tree
+      run_cmake_command(Envgen-instance-existing ${CMAKE_COMMAND} -E chdir ..
+              ${CMAKE_COMMAND} --build Envgen-build)
+      run_cmake_command(Envgen-instance-invalid ${CMAKE_COMMAND} ${source_dir})
+      unset(ENV{CMAKE_GENERATOR_INSTANCE})
+    endif()
+    unset(ENV{CMAKE_GENERATOR})
+  endif()
+endfunction()
+run_EnvironmentGenerator()
+
 if(RunCMake_GENERATOR STREQUAL "Ninja")
   # Use a single build tree for a few tests without cleaning.
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Build-build)
-- 
cgit v0.12