Browse Source

Merge topic 'cmake-language-exit-code'

1bb1769235 cmake_language: Add EXIT subcommand
4f160f7906 cmakemain: Return the SCRIPT_MODE exit code if it was set
b62dcbf5d2 cmMakefile: check cmake script mode exit code after command
3d9d504646 cmMakefile: Store the exit code from cmExecutionStatus to cmake instance
9f6c937408 Source/cmake.h: Add ScriptModeExitCode for proper storing exit code
1082b9cb9a cmExecutionStatus: Add ability to set optional custom exit code

Acked-by: Kitware Robot <[email protected]>
Acked-by: buildbot <[email protected]>
Acked-by: Leonid Pospelov <[email protected]>
Acked-by: NoMaY (a user of Renesas Rulz Japanese Forum) <[email protected]>
Merge-request: !8228
Brad King 1 year ago
parent
commit
fa4a499238
34 changed files with 126 additions and 5 deletions
  1. 23 0
      Help/command/cmake_language.rst
  2. 5 0
      Help/release/dev/cmake-language-exit.rst
  3. 26 0
      Source/cmCMakeLanguageCommand.cxx
  4. 8 0
      Source/cmExecutionStatus.h
  5. 11 0
      Source/cmMakefile.cxx
  6. 1 1
      Source/cmake.cxx
  7. 6 0
      Source/cmake.h
  8. 7 4
      Source/cmakemain.cxx
  9. 7 0
      Tests/RunCMake/cmake_language/RunCMakeTest.cmake
  10. 1 0
      Tests/RunCMake/cmake_language/exit_0-result.txt
  11. 2 0
      Tests/RunCMake/cmake_language/exit_0-stderr.txt
  12. 1 0
      Tests/RunCMake/cmake_language/exit_0.cmake
  13. 1 0
      Tests/RunCMake/cmake_language/exit_0_script-result.txt
  14. 0 0
      Tests/RunCMake/cmake_language/exit_0_script-stderr.txt
  15. 1 0
      Tests/RunCMake/cmake_language/exit_0_script.cmake
  16. 1 0
      Tests/RunCMake/cmake_language/exit_0_script_with_command-result.txt
  17. 0 0
      Tests/RunCMake/cmake_language/exit_0_script_with_command-stderr.txt
  18. 3 0
      Tests/RunCMake/cmake_language/exit_0_script_with_command.cmake
  19. 1 0
      Tests/RunCMake/cmake_language/exit_5-result.txt
  20. 2 0
      Tests/RunCMake/cmake_language/exit_5-stderr.txt
  21. 1 0
      Tests/RunCMake/cmake_language/exit_5.cmake
  22. 1 0
      Tests/RunCMake/cmake_language/exit_5_script-result.txt
  23. 0 0
      Tests/RunCMake/cmake_language/exit_5_script-stderr.txt
  24. 1 0
      Tests/RunCMake/cmake_language/exit_5_script.cmake
  25. 1 0
      Tests/RunCMake/cmake_language/exit_5_script_with_command-result.txt
  26. 0 0
      Tests/RunCMake/cmake_language/exit_5_script_with_command-stderr.txt
  27. 3 0
      Tests/RunCMake/cmake_language/exit_5_script_with_command.cmake
  28. 1 0
      Tests/RunCMake/cmake_language/exit_7_script_in_include-result.txt
  29. 0 0
      Tests/RunCMake/cmake_language/exit_7_script_in_include-stderr.txt
  30. 3 0
      Tests/RunCMake/cmake_language/exit_7_script_in_include.cmake
  31. 3 0
      Tests/RunCMake/cmake_language/exit_7_script_included_with_exit.cmake
  32. 1 0
      Tests/RunCMake/cmake_language/exit_8_script_in_recursive_cmake_language-result.txt
  33. 1 0
      Tests/RunCMake/cmake_language/exit_8_script_in_recursive_cmake_language-stderr.txt
  34. 3 0
      Tests/RunCMake/cmake_language/exit_8_script_in_recursive_cmake_language.cmake

+ 23 - 0
Help/command/cmake_language.rst

@@ -15,6 +15,7 @@ Synopsis
   cmake_language(`DEFER`_ <options>... CALL <command> [<arg>...])
   cmake_language(`SET_DEPENDENCY_PROVIDER`_ <command> SUPPORTED_METHODS <methods>...)
   cmake_language(`GET_MESSAGE_LOG_LEVEL`_ <out-var>)
+  cmake_language(`EXIT`_ <exit-code>)
 
 Introduction
 ^^^^^^^^^^^^
@@ -506,3 +507,25 @@ Getting current message log level
   If both the command line option and the variable are set, the command line
   option takes precedence. If neither are set, the default logging level
   is returned.
+
+Terminating Scripts
+^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.29
+
+.. _EXIT:
+.. _exit-code:
+
+.. code-block:: cmake
+
+.. signature::
+  cmake_language(EXIT <exit-code>)
+
+  Terminate the current :option:`cmake -P` script and exit with ``<exit-code>``.
+
+  This command works only in :ref:`script mode <Script Processing Mode>`.
+
+  The ``<exit-code>`` should be non-negative.
+  If ``<exit-code>`` is negative then the behavior
+  is unspecified (e.g., on Windows the error code -1
+  becomes ``0xffffffff``, and on Linux it becomes ``255``).

+ 5 - 0
Help/release/dev/cmake-language-exit.rst

@@ -0,0 +1,5 @@
+cmake-language-exit
+-------------------
+
+* The :command:`cmake_language()` command gained a new ``EXIT``
+  sub-command to exit scripts with a specified exit code.

+ 26 - 0
Source/cmCMakeLanguageCommand.cxx

@@ -398,6 +398,32 @@ bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args,
   if (!moreArgs()) {
     return FatalError(status, "called with incorrect number of arguments");
   }
+  if (expArgs[expArg] == "EXIT"_s) {
+    ++expArg; // consume "EXIT".
+
+    if (!moreArgs()) {
+      return FatalError(status, "EXIT requires one argument");
+    }
+
+    auto workingMode =
+      status.GetMakefile().GetCMakeInstance()->GetWorkingMode();
+    if (workingMode != cmake::SCRIPT_MODE) {
+      return FatalError(status, "EXIT can be used only in SCRIPT mode");
+    }
+
+    long retCode = 0;
+
+    if (!cmStrToLong(expArgs[expArg], &retCode)) {
+      return FatalError(status,
+                        cmStrCat("EXIT requires one integral argument, got \"",
+                                 expArgs[expArg], '\"'));
+    }
+
+    if (workingMode == cmake::SCRIPT_MODE) {
+      status.SetExitCode(static_cast<int>(retCode));
+    }
+    return true;
+  }
 
   if (expArgs[expArg] == "SET_DEPENDENCY_PROVIDER"_s) {
     finishArgs();

+ 8 - 0
Source/cmExecutionStatus.h

@@ -7,6 +7,8 @@
 #include <string>
 #include <vector>
 
+#include <cm/optional>
+
 class cmMakefile;
 
 /** \class cmExecutionStatus
@@ -53,6 +55,11 @@ public:
   void SetNestedError() { this->NestedError = true; }
   bool GetNestedError() const { return this->NestedError; }
 
+  void SetExitCode(int code) noexcept { this->ExitCode = code; }
+  bool HasExitCode() const noexcept { return this->ExitCode.has_value(); }
+  void CleanExitCode() noexcept { this->ExitCode.reset(); }
+  int GetExitCode() const noexcept { return this->ExitCode.value_or(-1); }
+
 private:
   cmMakefile& Makefile;
   std::string Error;
@@ -60,5 +67,6 @@ private:
   bool BreakInvoked = false;
   bool ContinueInvoked = false;
   bool NestedError = false;
+  cm::optional<int> ExitCode;
   std::vector<std::string> Variables;
 };

+ 11 - 0
Source/cmMakefile.cxx

@@ -529,6 +529,12 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
           cmSystemTools::SetFatalErrorOccurred();
         }
       }
+      if (this->GetCMakeInstance()->HasScriptModeExitCode() &&
+          this->GetCMakeInstance()->GetWorkingMode() == cmake::SCRIPT_MODE) {
+        // pass-through the exit code from inner cmake_language(EXIT) ,
+        // possibly from include() or similar command...
+        status.SetExitCode(this->GetCMakeInstance()->GetScriptModeExitCode());
+      }
     }
   } else {
     if (!cmSystemTools::GetFatalErrorOccurred()) {
@@ -898,6 +904,11 @@ void cmMakefile::RunListFile(cmListFile const& listFile,
     if (cmSystemTools::GetFatalErrorOccurred()) {
       break;
     }
+    if (status.HasExitCode()) {
+      // cmake_language EXIT was requested, early break.
+      this->GetCMakeInstance()->SetScriptModeExitCode(status.GetExitCode());
+      break;
+    }
     if (status.GetReturnInvoked()) {
       this->RaiseScope(status.GetReturnVariables());
       // Exit early due to return command.

+ 1 - 1
Source/cmake.cxx

@@ -2820,7 +2820,7 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure)
     if (cmSystemTools::GetErrorOccurredFlag()) {
       return -1;
     }
-    return 0;
+    return this->HasScriptModeExitCode() ? this->GetScriptModeExitCode() : 0;
   }
 
   // If MAKEFLAGS are given in the environment, remove the environment

+ 6 - 0
Source/cmake.h

@@ -835,7 +835,13 @@ private:
   std::string DebuggerDapLogFile;
 #endif
 
+  cm::optional<int> ScriptModeExitCode;
+
 public:
+  bool HasScriptModeExitCode() const { return ScriptModeExitCode.has_value(); }
+  void SetScriptModeExitCode(int code) { ScriptModeExitCode = code; }
+  int GetScriptModeExitCode() const { return ScriptModeExitCode.value_or(-1); }
+
   static cmDocumentationEntry CMAKE_STANDARD_OPTIONS_TABLE[18];
 };
 

+ 7 - 4
Source/cmakemain.cxx

@@ -389,13 +389,16 @@ int do_cmake(int ac, char const* const* av)
     }
   }
 
-  // Always return a non-negative value.  Windows tools do not always
-  // interpret negative return values as errors.
+  // Always return a non-negative value (except exit code from SCRIPT_MODE).
+  // Windows tools do not always interpret negative return values as errors.
   if (res != 0) {
+    auto scriptModeExitCode =
+      cm.HasScriptModeExitCode() ? cm.GetScriptModeExitCode() : 0;
+    res = scriptModeExitCode ? scriptModeExitCode : 1;
 #ifdef CMake_ENABLE_DEBUGGER
-    cm.StopDebuggerIfNeeded(1);
+    cm.StopDebuggerIfNeeded(res);
 #endif
-    return 1;
+    return res;
   }
 #ifdef CMake_ENABLE_DEBUGGER
   cm.StopDebuggerIfNeeded(0);

+ 7 - 0
Tests/RunCMake/cmake_language/RunCMakeTest.cmake

@@ -84,6 +84,13 @@ run_cmake(defer_get_call_id_var)
 run_cmake(defer_missing_arg)
 run_cmake(defer_missing_call)
 run_cmake(defer_unknown_option)
+run_cmake(exit_0)
+run_cmake(exit_5)
+run_cmake_script(exit_0_script)
+run_cmake_script(exit_5_script)
+run_cmake_script(exit_0_script_with_command)
+run_cmake_script(exit_7_script_in_include)
+run_cmake_script(exit_8_script_in_recursive_cmake_language)
 
 # Default log level
 run_cmake_command(

+ 1 - 0
Tests/RunCMake/cmake_language/exit_0-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/cmake_language/exit_0-stderr.txt

@@ -0,0 +1,2 @@
+CMake Error at exit_0.cmake:1 \(cmake_language\):
+  cmake_language EXIT can be used only in SCRIPT mode

+ 1 - 0
Tests/RunCMake/cmake_language/exit_0.cmake

@@ -0,0 +1 @@
+cmake_language(EXIT 0)

+ 1 - 0
Tests/RunCMake/cmake_language/exit_0_script-result.txt

@@ -0,0 +1 @@
+0

+ 0 - 0
Tests/RunCMake/cmake_language/exit_0_script-stderr.txt


+ 1 - 0
Tests/RunCMake/cmake_language/exit_0_script.cmake

@@ -0,0 +1 @@
+cmake_language(EXIT 0)

+ 1 - 0
Tests/RunCMake/cmake_language/exit_0_script_with_command-result.txt

@@ -0,0 +1 @@
+0

+ 0 - 0
Tests/RunCMake/cmake_language/exit_0_script_with_command-stderr.txt


+ 3 - 0
Tests/RunCMake/cmake_language/exit_0_script_with_command.cmake

@@ -0,0 +1,3 @@
+cmake_language(EXIT 0)
+
+message(FATAL_ERROR "cmake_language(EXIT 0) doesn't work")

+ 1 - 0
Tests/RunCMake/cmake_language/exit_5-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/cmake_language/exit_5-stderr.txt

@@ -0,0 +1,2 @@
+CMake Error at exit_5.cmake:1 \(cmake_language\):
+  cmake_language EXIT can be used only in SCRIPT mode

+ 1 - 0
Tests/RunCMake/cmake_language/exit_5.cmake

@@ -0,0 +1 @@
+cmake_language(EXIT 5)

+ 1 - 0
Tests/RunCMake/cmake_language/exit_5_script-result.txt

@@ -0,0 +1 @@
+5

+ 0 - 0
Tests/RunCMake/cmake_language/exit_5_script-stderr.txt


+ 1 - 0
Tests/RunCMake/cmake_language/exit_5_script.cmake

@@ -0,0 +1 @@
+cmake_language(EXIT 5)

+ 1 - 0
Tests/RunCMake/cmake_language/exit_5_script_with_command-result.txt

@@ -0,0 +1 @@
+5

+ 0 - 0
Tests/RunCMake/cmake_language/exit_5_script_with_command-stderr.txt


+ 3 - 0
Tests/RunCMake/cmake_language/exit_5_script_with_command.cmake

@@ -0,0 +1,3 @@
+cmake_language(EXIT 5)
+
+message(FATAL_ERROR "cmake_language(EXIT 5) doesn't work")

+ 1 - 0
Tests/RunCMake/cmake_language/exit_7_script_in_include-result.txt

@@ -0,0 +1 @@
+7

+ 0 - 0
Tests/RunCMake/cmake_language/exit_7_script_in_include-stderr.txt


+ 3 - 0
Tests/RunCMake/cmake_language/exit_7_script_in_include.cmake

@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/exit_7_script_included_with_exit.cmake)
+
+message(FATAL_ERROR "The cmake_language(EXIT 7) from include()-d script doesn't work")

+ 3 - 0
Tests/RunCMake/cmake_language/exit_7_script_included_with_exit.cmake

@@ -0,0 +1,3 @@
+cmake_language(EXIT 7)
+
+message(FATAL_ERROR "The include()-d script with EXIT 7 doesn't work")

+ 1 - 0
Tests/RunCMake/cmake_language/exit_8_script_in_recursive_cmake_language-result.txt

@@ -0,0 +1 @@
+8

+ 1 - 0
Tests/RunCMake/cmake_language/exit_8_script_in_recursive_cmake_language-stderr.txt

@@ -0,0 +1 @@
+

+ 3 - 0
Tests/RunCMake/cmake_language/exit_8_script_in_recursive_cmake_language.cmake

@@ -0,0 +1,3 @@
+cmake_language(EVAL CODE "cmake_language(EXIT 8)")
+
+message(FATAL_ERROR "The cmake_language EVAL of EXIT 8 test doesn't work")