From 4568d046c46a7357ab48ddfb1117bad39e65572c Mon Sep 17 00:00:00 2001
From: Kyle Edwards <kyle.edwards@kitware.com>
Date: Mon, 14 Jan 2019 12:27:14 -0500
Subject: Properties: Add CMAKE_ROLE global property

This property allows scripts to determine whether they're in project
mode, script mode, find-package mode, CTest, or CPack.
---
 Help/manual/cmake-properties.7.rst                 |  1 +
 Help/prop_gbl/CMAKE_ROLE.rst                       | 20 ++++++++++++
 Help/release/dev/cmake_role-global-property.rst    |  6 ++++
 Source/CPack/cmCPackGenerator.cxx                  |  3 +-
 Source/CPack/cpack.cxx                             |  3 +-
 Source/CTest/cmCTestBuildAndTestHandler.cxx        |  3 +-
 Source/CTest/cmCTestLaunch.cxx                     |  3 +-
 Source/CTest/cmCTestScriptHandler.cxx              |  2 +-
 Source/CTest/cmCTestTestHandler.cxx                |  2 +-
 Source/CursesDialog/ccmake.cxx                     |  3 +-
 Source/CursesDialog/cmCursesMainForm.cxx           |  2 +-
 Source/QtDialog/CMakeSetup.cxx                     |  2 +-
 Source/QtDialog/QCMake.cxx                         |  2 +-
 Source/cmCTest.cxx                                 |  2 +-
 Source/cmGlobalNinjaGenerator.cxx                  |  2 +-
 Source/cmGraphVizWriter.cxx                        |  3 +-
 Source/cmMakefile.cxx                              |  2 +-
 Source/cmQtAutoGenerator.cxx                       |  3 +-
 Source/cmServerProtocol.cxx                        |  3 +-
 Source/cmState.cxx                                 | 37 ++++++++++++++++++++++
 Source/cmState.h                                   | 17 ++++++++++
 Source/cmake.cxx                                   |  6 ++--
 Source/cmake.h                                     |  4 +--
 Source/cmakemain.cxx                               | 22 ++++++++++---
 Source/cmcmd.cxx                                   |  6 ++--
 Tests/RunCMake/CMakeLists.txt                      |  1 +
 .../CMakeRoleGlobalProperty/CMakeLists.txt         |  3 ++
 .../CMakeRoleGlobalProperty/CMakeLists.txt.in      |  4 +++
 .../CMakeRoleGlobalProperty/FindDummyPackage.cmake |  8 +++++
 .../RunCMake/CMakeRoleGlobalProperty/Project.cmake |  6 ++++
 .../CMakeRoleGlobalProperty/RunCMakeTest.cmake     |  7 ++++
 .../RunCMake/CMakeRoleGlobalProperty/Script.cmake  |  6 ++++
 .../CMakeRoleGlobalProperty/sub/CMakeLists.txt     |  4 +++
 .../RunCMake/CMakeRoleGlobalProperty/test.cmake.in |  7 ++++
 .../CPack/tests/EXTERNAL/create_package.cmake      |  5 +++
 35 files changed, 183 insertions(+), 27 deletions(-)
 create mode 100644 Help/prop_gbl/CMAKE_ROLE.rst
 create mode 100644 Help/release/dev/cmake_role-global-property.rst
 create mode 100644 Tests/RunCMake/CMakeRoleGlobalProperty/CMakeLists.txt
 create mode 100644 Tests/RunCMake/CMakeRoleGlobalProperty/CMakeLists.txt.in
 create mode 100644 Tests/RunCMake/CMakeRoleGlobalProperty/FindDummyPackage.cmake
 create mode 100644 Tests/RunCMake/CMakeRoleGlobalProperty/Project.cmake
 create mode 100644 Tests/RunCMake/CMakeRoleGlobalProperty/RunCMakeTest.cmake
 create mode 100644 Tests/RunCMake/CMakeRoleGlobalProperty/Script.cmake
 create mode 100644 Tests/RunCMake/CMakeRoleGlobalProperty/sub/CMakeLists.txt
 create mode 100644 Tests/RunCMake/CMakeRoleGlobalProperty/test.cmake.in

diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index df8f12c..02aaf4a 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -23,6 +23,7 @@ Properties of Global Scope
    /prop_gbl/AUTORCC_SOURCE_GROUP
    /prop_gbl/CMAKE_C_KNOWN_FEATURES
    /prop_gbl/CMAKE_CXX_KNOWN_FEATURES
+   /prop_gbl/CMAKE_ROLE
    /prop_gbl/DEBUG_CONFIGURATIONS
    /prop_gbl/DISABLED_FEATURES
    /prop_gbl/ENABLED_FEATURES
diff --git a/Help/prop_gbl/CMAKE_ROLE.rst b/Help/prop_gbl/CMAKE_ROLE.rst
new file mode 100644
index 0000000..27512fa
--- /dev/null
+++ b/Help/prop_gbl/CMAKE_ROLE.rst
@@ -0,0 +1,20 @@
+CMAKE_ROLE
+----------
+
+Tells what mode the current running script is in. Could be one of several
+values:
+
+``PROJECT``
+  Running in project mode (processing a ``CMakeLists.txt`` file).
+
+``SCRIPT``
+  Running in ``-P`` script mode.
+
+``FIND_PACKAGE``
+  Running in ``--find-package`` mode.
+
+``CTEST``
+  Running in CTest script mode.
+
+``CPACK``
+  Running in CPack.
diff --git a/Help/release/dev/cmake_role-global-property.rst b/Help/release/dev/cmake_role-global-property.rst
new file mode 100644
index 0000000..7b1fa0b
--- /dev/null
+++ b/Help/release/dev/cmake_role-global-property.rst
@@ -0,0 +1,6 @@
+cmake_role-global-property
+--------------------------
+
+* A new global property, :prop_gbl:`CMAKE_ROLE`, was added to allow scripts to
+  determine whether they're running in project mode, script mode, find-package
+  mode, CTest, or CPack.
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
index acd6650..b205105 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -18,6 +18,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
+#include "cmState.h"
 #include "cmStateSnapshot.h"
 #include "cmVersion.h"
 #include "cmWorkingDirectory.h"
@@ -690,7 +691,7 @@ int cmCPackGenerator::InstallCMakeProject(
                   "-   Install component: " << component << std::endl);
   }
 
-  cmake cm(cmake::RoleScript);
+  cmake cm(cmake::RoleScript, cmState::CPack);
   cm.SetHomeDirectory("");
   cm.SetHomeOutputDirectory("");
   cm.GetCurrentSnapshot().SetDefaultDefinitions();
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
index 4e49727..db9a0e7 100644
--- a/Source/CPack/cpack.cxx
+++ b/Source/CPack/cpack.cxx
@@ -24,6 +24,7 @@
 #include "cmDocumentationFormatter.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
+#include "cmState.h"
 #include "cmStateSnapshot.h"
 #include "cmSystemTools.h"
 #include "cmake.h"
@@ -208,7 +209,7 @@ int main(int argc, char const* const* argv)
   cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
               "Read CPack config file: " << cpackConfigFile << std::endl);
 
-  cmake cminst(cmake::RoleScript);
+  cmake cminst(cmake::RoleScript, cmState::CPack);
   cminst.SetHomeDirectory("");
   cminst.SetHomeOutputDirectory("");
   cminst.SetProgressCallback(cpackProgressCallback, nullptr);
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
index 668a387..d49fba2 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.cxx
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -6,6 +6,7 @@
 #include "cmCTestTestHandler.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
+#include "cmState.h"
 #include "cmSystemTools.h"
 #include "cmWorkingDirectory.h"
 #include "cmake.h"
@@ -163,7 +164,7 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
     return 1;
   }
 
-  cmake cm(cmake::RoleProject);
+  cmake cm(cmake::RoleProject, cmState::CTest);
   cm.SetHomeDirectory("");
   cm.SetHomeOutputDirectory("");
   std::string cmakeOutString;
diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx
index 6cd1c09..4facea2 100644
--- a/Source/CTest/cmCTestLaunch.cxx
+++ b/Source/CTest/cmCTestLaunch.cxx
@@ -15,6 +15,7 @@
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmProcessOutput.h"
+#include "cmState.h"
 #include "cmStateSnapshot.h"
 #include "cmSystemTools.h"
 #include "cmXMLWriter.h"
@@ -610,7 +611,7 @@ int cmCTestLaunch::Main(int argc, const char* const argv[])
 
 void cmCTestLaunch::LoadConfig()
 {
-  cmake cm(cmake::RoleScript);
+  cmake cm(cmake::RoleScript, cmState::CTest);
   cm.SetHomeDirectory("");
   cm.SetHomeOutputDirectory("");
   cm.GetCurrentSnapshot().SetDefaultDefinitions();
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index 30192c2..aa37ff9 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -280,7 +280,7 @@ void cmCTestScriptHandler::CreateCMake()
     delete this->GlobalGenerator;
     delete this->Makefile;
   }
-  this->CMake = new cmake(cmake::RoleScript);
+  this->CMake = new cmake(cmake::RoleScript, cmState::CTest);
   this->CMake->SetHomeDirectory("");
   this->CMake->SetHomeOutputDirectory("");
   this->CMake->GetCurrentSnapshot().SetDefaultDefinitions();
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index 9fd2299..acbe465 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -1676,7 +1676,7 @@ void cmCTestTestHandler::GetListOfTests()
   }
   cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                      "Constructing a list of tests" << std::endl, this->Quiet);
-  cmake cm(cmake::RoleScript);
+  cmake cm(cmake::RoleScript, cmState::CTest);
   cm.SetHomeDirectory("");
   cm.SetHomeOutputDirectory("");
   cm.GetCurrentSnapshot().SetDefaultDefinitions();
diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx
index a3e0717..6dc692e 100644
--- a/Source/CursesDialog/ccmake.cxx
+++ b/Source/CursesDialog/ccmake.cxx
@@ -6,6 +6,7 @@
 #include "cmCursesStandardIncludes.h"
 #include "cmDocumentation.h"
 #include "cmDocumentationEntry.h"
+#include "cmState.h"
 #include "cmSystemTools.h"
 #include "cmake.h"
 
@@ -83,7 +84,7 @@ int main(int argc, char const* const* argv)
   cmDocumentation doc;
   doc.addCMakeStandardDocSections();
   if (doc.CheckOptions(argc, argv)) {
-    cmake hcm(cmake::RoleInternal);
+    cmake hcm(cmake::RoleInternal, cmState::Unknown);
     hcm.SetHomeDirectory("");
     hcm.SetHomeOutputDirectory("");
     hcm.AddCMakePaths();
diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx
index 931797a..a75d913 100644
--- a/Source/CursesDialog/cmCursesMainForm.cxx
+++ b/Source/CursesDialog/cmCursesMainForm.cxx
@@ -41,7 +41,7 @@ cmCursesMainForm::cmCursesMainForm(std::vector<std::string> const& args,
     "Welcome to ccmake, curses based user interface for CMake.");
   this->HelpMessage.push_back("");
   this->HelpMessage.push_back(s_ConstHelpMessage);
-  this->CMakeInstance = new cmake(cmake::RoleProject);
+  this->CMakeInstance = new cmake(cmake::RoleProject, cmState::Project);
   this->CMakeInstance->SetCMakeEditCommand(
     cmSystemTools::GetCMakeCursesCommand());
 
diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx
index 98cf8b0..b4307bb 100644
--- a/Source/QtDialog/CMakeSetup.cxx
+++ b/Source/QtDialog/CMakeSetup.cxx
@@ -64,7 +64,7 @@ int main(int argc, char** argv)
   doc.addCMakeStandardDocSections();
   if (argc2 > 1 && doc.CheckOptions(argc2, argv2)) {
     // Construct and print requested documentation.
-    cmake hcm(cmake::RoleInternal);
+    cmake hcm(cmake::RoleInternal, cmState::Unknown);
     hcm.SetHomeDirectory("");
     hcm.SetHomeOutputDirectory("");
     hcm.AddCMakePaths();
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
index 0133b88..9a6784e 100644
--- a/Source/QtDialog/QCMake.cxx
+++ b/Source/QtDialog/QCMake.cxx
@@ -27,7 +27,7 @@ QCMake::QCMake(QObject* p)
   cmSystemTools::SetStdoutCallback(QCMake::stdoutCallback, this);
   cmSystemTools::SetStderrCallback(QCMake::stderrCallback, this);
 
-  this->CMakeInstance = new cmake(cmake::RoleProject);
+  this->CMakeInstance = new cmake(cmake::RoleProject, cmState::Project);
   this->CMakeInstance->SetCMakeEditCommand(
     cmSystemTools::GetCMakeGUICommand());
   this->CMakeInstance->SetProgressCallback(QCMake::progressCallback, this);
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index 65c0d91..1c0d9f6 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -429,7 +429,7 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
     }
   }
 
-  cmake cm(cmake::RoleScript);
+  cmake cm(cmake::RoleScript, cmState::CTest);
   cm.SetHomeDirectory("");
   cm.SetHomeOutputDirectory("");
   cm.GetCurrentSnapshot().SetDefaultDefinitions();
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 57d341a..e7b0981 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -1939,7 +1939,7 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
     }
   }
 
-  cmake cm(cmake::RoleInternal);
+  cmake cm(cmake::RoleInternal, cmState::Unknown);
   cm.SetHomeDirectory(dir_top_src);
   cm.SetHomeOutputDirectory(dir_top_bld);
   std::unique_ptr<cmGlobalNinjaGenerator> ggd(
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx
index 199c8e2..4b60279 100644
--- a/Source/cmGraphVizWriter.cxx
+++ b/Source/cmGraphVizWriter.cxx
@@ -13,6 +13,7 @@
 #include "cmGlobalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
+#include "cmState.h"
 #include "cmStateSnapshot.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
@@ -172,7 +173,7 @@ cmGraphVizWriter::cmGraphVizWriter(const cmGlobalGenerator* globalGenerator)
 void cmGraphVizWriter::ReadSettings(const char* settingsFileName,
                                     const char* fallbackSettingsFileName)
 {
-  cmake cm(cmake::RoleScript);
+  cmake cm(cmake::RoleScript, cmState::Unknown);
   cm.SetHomeDirectory("");
   cm.SetHomeOutputDirectory("");
   cm.GetCurrentSnapshot().SetDefaultDefinitions();
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 274c631..3ff576e 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -3374,7 +3374,7 @@ int cmMakefile::TryCompile(const std::string& srcdir,
   // make sure the same generator is used
   // use this program as the cmake to be run, it should not
   // be run that way but the cmake object requires a vailid path
-  cmake cm(cmake::RoleProject);
+  cmake cm(cmake::RoleProject, cmState::Project);
   cm.SetIsInTryCompile(true);
   cmGlobalGenerator* gg =
     cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName());
diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx
index f2f4cad..c5d5d7c 100644
--- a/Source/cmQtAutoGenerator.cxx
+++ b/Source/cmQtAutoGenerator.cxx
@@ -8,6 +8,7 @@
 #include "cmAlgorithms.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
+#include "cmState.h"
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
 #include "cmSystemTools.h"
@@ -686,7 +687,7 @@ bool cmQtAutoGenerator::Run(std::string const& infoFile,
 
   bool success = false;
   {
-    cmake cm(cmake::RoleScript);
+    cmake cm(cmake::RoleScript, cmState::Unknown);
     cm.SetHomeOutputDirectory(InfoDir());
     cm.SetHomeDirectory(InfoDir());
     cm.GetCurrentSnapshot().SetDefaultDefinitions();
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
index 6dbfd10..11a3f46 100644
--- a/Source/cmServerProtocol.cxx
+++ b/Source/cmServerProtocol.cxx
@@ -130,7 +130,8 @@ bool cmServerProtocol::Activate(cmServer* server,
 {
   assert(server);
   this->m_Server = server;
-  this->m_CMakeInstance = cm::make_unique<cmake>(cmake::RoleProject);
+  this->m_CMakeInstance =
+    cm::make_unique<cmake>(cmake::RoleProject, cmState::Project);
   const bool result = this->DoActivate(request, errorMessage);
   if (!result) {
     this->m_CMakeInstance = nullptr;
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index f664000..cf170b0 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -539,6 +539,9 @@ const char* cmState::GetGlobalProperty(const std::string& prop)
     std::string langs;
     langs = cmJoin(this->EnabledLanguages, ";");
     this->SetGlobalProperty("ENABLED_LANGUAGES", langs.c_str());
+  } else if (prop == "CMAKE_ROLE") {
+    std::string mode = this->GetModeString();
+    this->SetGlobalProperty("CMAKE_ROLE", mode.c_str());
   }
 #define STRING_LIST_ELEMENT(F) ";" #F
   if (prop == "CMAKE_C_KNOWN_FEATURES") {
@@ -643,6 +646,40 @@ unsigned int cmState::GetCacheMinorVersion() const
   return this->CacheManager->GetCacheMinorVersion();
 }
 
+cmState::Mode cmState::GetMode() const
+{
+  return this->CurrentMode;
+}
+
+std::string cmState::GetModeString() const
+{
+  return ModeToString(this->CurrentMode);
+}
+
+void cmState::SetMode(cmState::Mode mode)
+{
+  this->CurrentMode = mode;
+}
+
+std::string cmState::ModeToString(cmState::Mode mode)
+{
+  switch (mode) {
+    case Project:
+      return "PROJECT";
+    case Script:
+      return "SCRIPT";
+    case FindPackage:
+      return "FIND_PACKAGE";
+    case CTest:
+      return "CTEST";
+    case CPack:
+      return "CPACK";
+    case Unknown:
+      return "UNKNOWN";
+  }
+  return "UNKNOWN";
+}
+
 std::string const& cmState::GetBinaryDirectory() const
 {
   return this->BinaryDirectory;
diff --git a/Source/cmState.h b/Source/cmState.h
index abe93ed..dfd6d2c 100644
--- a/Source/cmState.h
+++ b/Source/cmState.h
@@ -35,6 +35,16 @@ public:
   cmState();
   ~cmState();
 
+  enum Mode
+  {
+    Unknown,
+    Project,
+    Script,
+    FindPackage,
+    CTest,
+    CPack,
+  };
+
   static const char* GetTargetTypeName(cmStateEnums::TargetType targetType);
 
   cmStateSnapshot CreateBaseSnapshot();
@@ -166,6 +176,12 @@ public:
   unsigned int GetCacheMajorVersion() const;
   unsigned int GetCacheMinorVersion() const;
 
+  Mode GetMode() const;
+  std::string GetModeString() const;
+  void SetMode(Mode mode);
+
+  static std::string ModeToString(Mode mode);
+
 private:
   friend class cmake;
   void AddCacheEntry(const std::string& key, const char* value,
@@ -210,6 +226,7 @@ private:
   bool MinGWMake = false;
   bool NMake = false;
   bool MSYSShell = false;
+  Mode CurrentMode = Unknown;
 };
 
 #endif
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index c65bd2e..9fcfbde 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -126,7 +126,7 @@ void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/,
   cm->MarkCliAsUsed(variable);
 }
 
-cmake::cmake(Role role)
+cmake::cmake(Role role, cmState::Mode mode)
 {
   this->Trace = false;
   this->TraceExpand = false;
@@ -140,6 +140,7 @@ cmake::cmake(Role role)
   this->FileComparison = new cmFileTimeComparison;
 
   this->State = new cmState;
+  this->State->SetMode(mode);
   this->CurrentSnapshot = this->State->CreateBaseSnapshot();
   this->Messenger = new cmMessenger;
 
@@ -2023,7 +2024,8 @@ int cmake::CheckBuildSystem()
 
   // Read the rerun check file and use it to decide whether to do the
   // global generate.
-  cmake cm(RoleScript); // Actually, all we need is the `set` command.
+  // Actually, all we need is the `set` command.
+  cmake cm(RoleScript, cmState::Unknown);
   cm.SetHomeDirectory("");
   cm.SetHomeOutputDirectory("");
   cm.GetCurrentSnapshot().SetDefaultDefinitions();
diff --git a/Source/cmake.h b/Source/cmake.h
index 9891857..cd8c622 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -15,6 +15,7 @@
 #include "cmInstalledFile.h"
 #include "cmListFileCache.h"
 #include "cmMessageType.h"
+#include "cmState.h"
 #include "cmStateSnapshot.h"
 #include "cmStateTypes.h"
 
@@ -29,7 +30,6 @@ class cmGlobalGenerator;
 class cmGlobalGeneratorFactory;
 class cmMakefile;
 class cmMessenger;
-class cmState;
 class cmVariableWatch;
 struct cmDocumentationEntry;
 
@@ -113,7 +113,7 @@ public:
   static const int DEFAULT_BUILD_PARALLEL_LEVEL = 0;
 
   /// Default constructor
-  cmake(Role role);
+  cmake(Role role, cmState::Mode mode);
   /// Destructor
   ~cmake();
 
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index e52f2b3..84d1414 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -217,7 +217,7 @@ int do_cmake(int ac, char const* const* av)
   doc.addCMakeStandardDocSections();
   if (doc.CheckOptions(ac, av)) {
     // Construct and print requested documentation.
-    cmake hcm(cmake::RoleInternal);
+    cmake hcm(cmake::RoleInternal, cmState::Unknown);
     hcm.SetHomeDirectory("");
     hcm.SetHomeOutputDirectory("");
     hcm.AddCMakePaths();
@@ -299,7 +299,7 @@ int do_cmake(int ac, char const* const* av)
     }
   }
   if (sysinfo) {
-    cmake cm(cmake::RoleProject);
+    cmake cm(cmake::RoleProject, cmState::Project);
     cm.SetHomeDirectory("");
     cm.SetHomeOutputDirectory("");
     int ret = cm.GetSystemInformation(args);
@@ -307,7 +307,19 @@ int do_cmake(int ac, char const* const* av)
   }
   cmake::Role const role =
     workingMode == cmake::SCRIPT_MODE ? cmake::RoleScript : cmake::RoleProject;
-  cmake cm(role);
+  cmState::Mode mode = cmState::Unknown;
+  switch (workingMode) {
+    case cmake::NORMAL_MODE:
+      mode = cmState::Project;
+      break;
+    case cmake::SCRIPT_MODE:
+      mode = cmState::Script;
+      break;
+    case cmake::FIND_PACKAGE_MODE:
+      mode = cmState::FindPackage;
+      break;
+  }
+  cmake cm(role, mode);
   cm.SetHomeDirectory("");
   cm.SetHomeOutputDirectory("");
   cmSystemTools::SetMessageCallback(cmakemainMessageCallback, &cm);
@@ -463,7 +475,7 @@ static int do_build(int ac, char const* const* av)
     return 1;
   }
 
-  cmake cm(cmake::RoleInternal);
+  cmake cm(cmake::RoleInternal, cmState::Unknown);
   cmSystemTools::SetMessageCallback(cmakemainMessageCallback, &cm);
   cm.SetProgressCallback(cmakemainProgressCallback, &cm);
   return cm.Build(jobs, dir, target, config, nativeOptions, clean);
@@ -501,7 +513,7 @@ static int do_open(int ac, char const* const* av)
     return 1;
   }
 
-  cmake cm(cmake::RoleInternal);
+  cmake cm(cmake::RoleInternal, cmState::Unknown);
   cmSystemTools::SetMessageCallback(cmakemainMessageCallback, &cm);
   cm.SetProgressCallback(cmakemainProgressCallback, &cm);
   return cm.Open(dir, false) ? 0 : 1;
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index b645ef1..ee8df35 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -9,6 +9,7 @@
 #include "cmMakefile.h"
 #include "cmQtAutoGeneratorMocUic.h"
 #include "cmQtAutoGeneratorRcc.h"
+#include "cmState.h"
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
 #include "cmSystemTools.h"
@@ -721,7 +722,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
         std::cerr << "-E capabilities accepts no additional arguments\n";
         return 1;
       }
-      cmake cm(cmake::RoleInternal);
+      cmake cm(cmake::RoleInternal, cmState::Unknown);
 #if defined(CMAKE_BUILD_WITH_CMAKE)
       std::cout << cm.ReportCapabilities(true);
 #else
@@ -898,7 +899,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
       const bool verbose = isCMakeVerbose();
 
       // Create a cmake object instance to process dependencies.
-      cmake cm(cmake::RoleScript); // All we need is the `set` command.
+      // All we need is the `set` command.
+      cmake cm(cmake::RoleScript, cmState::Unknown);
       std::string gen;
       std::string homeDir;
       std::string startDir;
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 358521b..c8653b4 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -155,6 +155,7 @@ add_RunCMake_test(BuildDepends)
 if(UNIX AND "${CMAKE_GENERATOR}" MATCHES "Unix Makefiles|Ninja")
   add_RunCMake_test(Byproducts)
 endif()
+add_RunCMake_test(CMakeRoleGlobalProperty)
 if(UNIX AND "${CMAKE_GENERATOR}" MATCHES "Unix Makefiles|Ninja")
   add_RunCMake_test(CompilerChange)
 endif()
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/CMakeLists.txt b/Tests/RunCMake/CMakeRoleGlobalProperty/CMakeLists.txt
new file mode 100644
index 0000000..44025d3
--- /dev/null
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.12)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/CMakeLists.txt.in b/Tests/RunCMake/CMakeRoleGlobalProperty/CMakeLists.txt.in
new file mode 100644
index 0000000..913239c
--- /dev/null
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/CMakeLists.txt.in
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.1)
+project(CTestStart@CASE_NAME@ NONE)
+include(CTest)
+add_test(NAME RunCMakeVersion COMMAND "${CMAKE_COMMAND}" --version)
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/FindDummyPackage.cmake b/Tests/RunCMake/CMakeRoleGlobalProperty/FindDummyPackage.cmake
new file mode 100644
index 0000000..8299042
--- /dev/null
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/FindDummyPackage.cmake
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.12)
+
+get_property(role GLOBAL PROPERTY CMAKE_ROLE)
+if(NOT role STREQUAL "FIND_PACKAGE")
+  message(SEND_ERROR "CMAKE_ROLE property is \"${role}\", should be \"FIND_PACKAGE\"")
+endif()
+
+set(DummyPackage_FOUND 1)
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/Project.cmake b/Tests/RunCMake/CMakeRoleGlobalProperty/Project.cmake
new file mode 100644
index 0000000..c0b6a48
--- /dev/null
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/Project.cmake
@@ -0,0 +1,6 @@
+get_property(role GLOBAL PROPERTY CMAKE_ROLE)
+if(NOT role STREQUAL "PROJECT")
+  message(SEND_ERROR "CMAKE_ROLE property is \"${role}\", should be \"PROJECT\"")
+endif()
+
+add_subdirectory(sub)
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/RunCMakeTest.cmake b/Tests/RunCMake/CMakeRoleGlobalProperty/RunCMakeTest.cmake
new file mode 100644
index 0000000..b840317
--- /dev/null
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/RunCMakeTest.cmake
@@ -0,0 +1,7 @@
+include(RunCMake)
+include(RunCTest)
+
+run_cmake(Project)
+run_cmake_command(Script "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_LIST_DIR}/Script.cmake")
+run_cmake_command(FindPackage "${CMAKE_COMMAND}" --find-package -DNAME=DummyPackage -DCOMPILER_ID=GNU -DLANGUAGE=CXX -DMODE=EXIST "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}")
+run_ctest(CTest)
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/Script.cmake b/Tests/RunCMake/CMakeRoleGlobalProperty/Script.cmake
new file mode 100644
index 0000000..371edbc
--- /dev/null
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/Script.cmake
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.12)
+
+get_property(role GLOBAL PROPERTY CMAKE_ROLE)
+if(NOT role STREQUAL "SCRIPT")
+  message(SEND_ERROR "CMAKE_ROLE property is \"${role}\", should be \"SCRIPT\"")
+endif()
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/sub/CMakeLists.txt b/Tests/RunCMake/CMakeRoleGlobalProperty/sub/CMakeLists.txt
new file mode 100644
index 0000000..8ecf671
--- /dev/null
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/sub/CMakeLists.txt
@@ -0,0 +1,4 @@
+get_property(role GLOBAL PROPERTY CMAKE_ROLE)
+if(NOT role STREQUAL "PROJECT")
+  message(SEND_ERROR "CMAKE_ROLE property is \"${role}\", should be \"PROJECT\"")
+endif()
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/test.cmake.in b/Tests/RunCMake/CMakeRoleGlobalProperty/test.cmake.in
new file mode 100644
index 0000000..4e2c085
--- /dev/null
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/test.cmake.in
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.12)
+set(CTEST_RUN_CURRENT_SCRIPT 0)
+
+get_property(role GLOBAL PROPERTY CMAKE_ROLE)
+if(NOT role STREQUAL "CTEST")
+  message(SEND_ERROR "CMAKE_ROLE property is \"${role}\", should be \"CTEST\"")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/EXTERNAL/create_package.cmake b/Tests/RunCMake/CPack/tests/EXTERNAL/create_package.cmake
index 2d7f993..6f7c4c2 100644
--- a/Tests/RunCMake/CPack/tests/EXTERNAL/create_package.cmake
+++ b/Tests/RunCMake/CPack/tests/EXTERNAL/create_package.cmake
@@ -1,5 +1,10 @@
 message("This script could run an external packaging tool")
 
+get_property(role GLOBAL PROPERTY CMAKE_ROLE)
+if(NOT role STREQUAL "CPACK")
+  message(SEND_ERROR "CMAKE_ROLE property is \"${role}\", should be \"CPACK\"")
+endif()
+
 function(expect_variable VAR)
   if(NOT ${VAR})
     message(FATAL_ERROR "${VAR} is unexpectedly not set")
-- 
cgit v0.12