فهرست منبع

cmake_command: Add command to EVAL a CMake script as a string

Cristian Adam 5 سال پیش
والد
کامیت
598b676b5e
24فایلهای تغییر یافته به همراه183 افزوده شده و 37 حذف شده
  1. 52 2
      Help/command/cmake_command.rst
  2. 1 1
      Help/release/dev/cmake_command-command.rst
  3. 3 11
      Source/LexerParser/cmListFileLexer.c
  4. 3 11
      Source/LexerParser/cmListFileLexer.in.l
  5. 24 3
      Source/cmCMakeCommand.cxx
  6. 43 8
      Source/cmListFileCache.cxx
  7. 3 0
      Source/cmListFileCache.h
  8. 21 0
      Source/cmMakefile.cxx
  9. 3 0
      Source/cmMakefile.h
  10. 1 1
      Tests/RunCMake/Syntax/CommandEOF-stderr.txt
  11. 5 0
      Tests/RunCMake/cmake_command/RunCMakeTest.cmake
  12. 1 0
      Tests/RunCMake/cmake_command/cmake_command_eval_message-stderr.txt
  13. 1 0
      Tests/RunCMake/cmake_command/cmake_command_eval_message.cmake
  14. 1 0
      Tests/RunCMake/cmake_command/cmake_command_eval_message_fatal_error-result.txt
  15. 5 0
      Tests/RunCMake/cmake_command/cmake_command_eval_message_fatal_error-stderr.txt
  16. 5 0
      Tests/RunCMake/cmake_command/cmake_command_eval_message_fatal_error.cmake
  17. 1 0
      Tests/RunCMake/cmake_command/cmake_command_eval_no_code-result.txt
  18. 2 0
      Tests/RunCMake/cmake_command/cmake_command_eval_no_code-stderr.txt
  19. 1 0
      Tests/RunCMake/cmake_command/cmake_command_eval_no_code.cmake
  20. 1 0
      Tests/RunCMake/cmake_command/cmake_command_eval_no_parameters-result.txt
  21. 2 0
      Tests/RunCMake/cmake_command/cmake_command_eval_no_parameters-stderr.txt
  22. 1 0
      Tests/RunCMake/cmake_command/cmake_command_eval_no_parameters.cmake
  23. 1 0
      Tests/RunCMake/cmake_command/cmake_command_eval_variable_outside_message-stderr.txt
  24. 2 0
      Tests/RunCMake/cmake_command/cmake_command_eval_variable_outside_message.cmake

+ 52 - 2
Help/command/cmake_command.rst

@@ -9,6 +9,7 @@ Synopsis
 .. parsed-literal::
 
   cmake_command(`INVOKE`_ <command> [<args>...])
+  cmake_command(`EVAL`_ CODE <code>...)
 
 Introduction
 ^^^^^^^^^^^^
@@ -16,8 +17,10 @@ Introduction
 This command will call meta-operations on built-in CMake commands or
 those created via the :command:`macro` or :command:`function` commands.
 
-Invoking
-^^^^^^^^
+``cmake_command`` does not introduce a new variable or policy scope.
+
+Invoking Commands
+^^^^^^^^^^^^^^^^^
 
 .. _INVOKE:
 
@@ -38,3 +41,50 @@ is equivalent to
 .. code-block:: cmake
 
   message(STATUS "Hello World!")
+
+Evaluating Code
+^^^^^^^^^^^^^^^
+
+.. _EVAL:
+
+.. code-block:: cmake
+
+  cmake_command(EVAL CODE <code>...)
+
+Evaluates the ``<code>...`` as CMake code.
+
+For example, the code:
+
+.. code-block:: cmake
+
+  set(A TRUE)
+  set(B TRUE)
+  set(C TRUE)
+  set(condition "(A AND B) OR C")
+
+  cmake_command(EVAL CODE "
+    if (${condition})
+      message(STATUS TRUE)
+    else()
+      message(STATUS FALSE)
+    endif()"
+  )
+
+is equivalent to
+
+.. code-block:: cmake
+
+  set(A TRUE)
+  set(B TRUE)
+  set(C TRUE)
+  set(condition "(A AND B) OR C")
+
+  file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/eval.cmake "
+    if (${condition})
+      message(STATUS TRUE)
+    else()
+      message(STATUS FALSE)
+    endif()"
+  )
+
+  include(${CMAKE_CURRENT_BINARY_DIR}/eval.cmake)

+ 1 - 1
Help/release/dev/cmake_command-command.rst

@@ -3,4 +3,4 @@ cmake_command
 
 * The :command:`cmake_command()` command was added for meta-operations on
   scripted or built-in commands, starting with a mode to ``INVOKE`` other
-  commands.
+  commands, and ``EVAL CODE`` to inplace evaluate a CMake script.

+ 3 - 11
Source/LexerParser/cmListFileLexer.c

@@ -2787,7 +2787,7 @@ int cmListFileLexer_SetString(cmListFileLexer* lexer, const char* text)
 /*--------------------------------------------------------------------------*/
 cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer)
 {
-  if (!lexer->file) {
+  if (!lexer->file && !lexer->string_buffer) {
     return 0;
   }
   if (cmListFileLexer_yylex(lexer->scanner, lexer)) {
@@ -2801,21 +2801,13 @@ cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer)
 /*--------------------------------------------------------------------------*/
 long cmListFileLexer_GetCurrentLine(cmListFileLexer* lexer)
 {
-  if (lexer->file) {
-    return lexer->line;
-  } else {
-    return 0;
-  }
+  return lexer->line;
 }
 
 /*--------------------------------------------------------------------------*/
 long cmListFileLexer_GetCurrentColumn(cmListFileLexer* lexer)
 {
-  if (lexer->file) {
-    return lexer->column;
-  } else {
-    return 0;
-  }
+  return lexer->column;
 }
 
 /*--------------------------------------------------------------------------*/

+ 3 - 11
Source/LexerParser/cmListFileLexer.in.l

@@ -500,7 +500,7 @@ int cmListFileLexer_SetString(cmListFileLexer* lexer, const char* text)
 /*--------------------------------------------------------------------------*/
 cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer)
 {
-  if (!lexer->file) {
+  if (!lexer->file && !lexer->string_buffer) {
     return 0;
   }
   if (cmListFileLexer_yylex(lexer->scanner, lexer)) {
@@ -514,21 +514,13 @@ cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer)
 /*--------------------------------------------------------------------------*/
 long cmListFileLexer_GetCurrentLine(cmListFileLexer* lexer)
 {
-  if (lexer->file) {
-    return lexer->line;
-  } else {
-    return 0;
-  }
+  return lexer->line;
 }
 
 /*--------------------------------------------------------------------------*/
 long cmListFileLexer_GetCurrentColumn(cmListFileLexer* lexer)
 {
-  if (lexer->file) {
-    return lexer->column;
-  } else {
-    return 0;
-  }
+  return lexer->column;
 }
 
 /*--------------------------------------------------------------------------*/

+ 24 - 3
Source/cmCMakeCommand.cxx

@@ -2,11 +2,14 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCMakeCommand.h"
 
+#include <algorithm>
 #include <cstddef>
 
 #include "cmExecutionStatus.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
 
 bool cmCMakeCommand(std::vector<std::string> const& args,
                     cmExecutionStatus& status)
@@ -19,6 +22,8 @@ bool cmCMakeCommand(std::vector<std::string> const& args,
   cmMakefile& makefile = status.GetMakefile();
   cmListFileContext context = makefile.GetExecutionContext();
 
+  bool result = false;
+
   if (args[0] == "INVOKE") {
     if (args.size() == 1) {
       status.SetError("called with incorrect number of arguments");
@@ -39,9 +44,25 @@ bool cmCMakeCommand(std::vector<std::string> const& args,
       func.Arguments.emplace_back(lfarg);
     }
 
-    return makefile.ExecuteCommand(func, status);
+    result = makefile.ExecuteCommand(func, status);
+  } else if (args[0] == "EVAL") {
+    if (args.size() < 2) {
+      status.SetError("called with incorrect number of arguments");
+      return false;
+    }
+
+    auto code_iter = std::find(args.begin(), args.end(), "CODE");
+    if (code_iter == args.end()) {
+      status.SetError("called without CODE argument");
+      return false;
+    }
+
+    const std::string code = cmJoin(cmMakeRange(++code_iter, args.end()), " ");
+    result = makefile.ReadListFileAsString(
+      code, cmStrCat(context.FilePath, ":", context.Line, ":EVAL"));
+  } else {
+    status.SetError("called with unknown meta-operation");
   }
 
-  status.SetError("called with unknown meta-operation");
-  return false;
+  return result;
 }

+ 43 - 8
Source/cmListFileCache.cxx

@@ -26,13 +26,15 @@ cmCommandContext::cmCommandName& cmCommandContext::cmCommandName::operator=(
 struct cmListFileParser
 {
   cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt,
-                   cmMessenger* messenger, const char* filename);
+                   cmMessenger* messenger);
   ~cmListFileParser();
   cmListFileParser(const cmListFileParser&) = delete;
   cmListFileParser& operator=(const cmListFileParser&) = delete;
   void IssueFileOpenError(std::string const& text) const;
   void IssueError(std::string const& text) const;
-  bool ParseFile();
+  bool ParseFile(const char* filename);
+  bool ParseString(const char* str, const char* virtual_filename);
+  bool Parse();
   bool ParseFunction(const char* name, long line);
   bool AddArgument(cmListFileLexer_Token* token,
                    cmListFileArgument::Delimiter delim);
@@ -51,12 +53,11 @@ struct cmListFileParser
 };
 
 cmListFileParser::cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt,
-                                   cmMessenger* messenger,
-                                   const char* filename)
+                                   cmMessenger* messenger)
   : ListFile(lf)
   , Backtrace(std::move(lfbt))
   , Messenger(messenger)
-  , FileName(filename)
+  , FileName(nullptr)
   , Lexer(cmListFileLexer_New())
 {
 }
@@ -83,8 +84,10 @@ void cmListFileParser::IssueError(const std::string& text) const
   cmSystemTools::SetFatalErrorOccured();
 }
 
-bool cmListFileParser::ParseFile()
+bool cmListFileParser::ParseFile(const char* filename)
 {
+  this->FileName = filename;
+
   // Open the file.
   cmListFileLexer_BOM bom;
   if (!cmListFileLexer_SetFileName(this->Lexer, this->FileName, &bom)) {
@@ -107,6 +110,24 @@ bool cmListFileParser::ParseFile()
     return false;
   }
 
+  return Parse();
+}
+
+bool cmListFileParser::ParseString(const char* str,
+                                   const char* virtual_filename)
+{
+  this->FileName = virtual_filename;
+
+  if (!cmListFileLexer_SetString(this->Lexer, str)) {
+    this->IssueFileOpenError("cmListFileCache: cannot allocate buffer.");
+    return false;
+  }
+
+  return Parse();
+}
+
+bool cmListFileParser::Parse()
+{
   // Use a simple recursive-descent parser to process the token
   // stream.
   bool haveNewline = true;
@@ -155,8 +176,22 @@ bool cmListFile::ParseFile(const char* filename, cmMessenger* messenger,
   bool parseError = false;
 
   {
-    cmListFileParser parser(this, lfbt, messenger, filename);
-    parseError = !parser.ParseFile();
+    cmListFileParser parser(this, lfbt, messenger);
+    parseError = !parser.ParseFile(filename);
+  }
+
+  return !parseError;
+}
+
+bool cmListFile::ParseString(const char* str, const char* virtual_filename,
+                             cmMessenger* messenger,
+                             const cmListFileBacktrace& lfbt)
+{
+  bool parseError = false;
+
+  {
+    cmListFileParser parser(this, lfbt, messenger);
+    parseError = !parser.ParseString(str, virtual_filename);
   }
 
   return !parseError;

+ 3 - 0
Source/cmListFileCache.h

@@ -184,6 +184,9 @@ struct cmListFile
   bool ParseFile(const char* path, cmMessenger* messenger,
                  cmListFileBacktrace const& lfbt);
 
+  bool ParseString(const char* str, const char* virtual_filename,
+                   cmMessenger* messenger, cmListFileBacktrace const& lfbt);
+
   std::vector<cmListFileFunction> Functions;
 };
 

+ 21 - 0
Source/cmMakefile.cxx

@@ -684,6 +684,27 @@ bool cmMakefile::ReadListFile(const std::string& filename)
   return true;
 }
 
+bool cmMakefile::ReadListFileAsString(const std::string& content,
+                                      const std::string& virtualFileName)
+{
+  std::string filenametoread = cmSystemTools::CollapseFullPath(
+    virtualFileName, this->GetCurrentSourceDirectory());
+
+  ListFileScope scope(this, filenametoread);
+
+  cmListFile listFile;
+  if (!listFile.ParseString(content.c_str(), virtualFileName.c_str(),
+                            this->GetMessenger(), this->Backtrace)) {
+    return false;
+  }
+
+  this->ReadListFile(listFile, filenametoread);
+  if (cmSystemTools::GetFatalErrorOccured()) {
+    scope.Quiet();
+  }
+  return true;
+}
+
 void cmMakefile::ReadListFile(cmListFile const& listFile,
                               std::string const& filenametoread)
 {

+ 3 - 0
Source/cmMakefile.h

@@ -117,6 +117,9 @@ public:
 
   bool ReadListFile(const std::string& filename);
 
+  bool ReadListFileAsString(const std::string& content,
+                            const std::string& virtualFileName);
+
   bool ReadDependentFile(const std::string& filename,
                          bool noPolicyScope = true);
 

+ 1 - 1
Tests/RunCMake/Syntax/CommandEOF-stderr.txt

@@ -1,4 +1,4 @@
-^CMake Error in CommandEOF.cmake:
+^CMake Error at CommandEOF.cmake:1:
   Unexpected end of file.
 
   Parse error.  Function missing opening "\(".

+ 5 - 0
Tests/RunCMake/cmake_command/RunCMakeTest.cmake

@@ -6,3 +6,8 @@ run_cmake(cmake_command_invoke_message)
 run_cmake(cmake_command_invoke_message_fatal_error)
 run_cmake(cmake_command_invoke_no_parameters)
 run_cmake(cmake_command_invoke_unknown_function)
+run_cmake(cmake_command_eval_message)
+run_cmake(cmake_command_eval_message_fatal_error)
+run_cmake(cmake_command_eval_no_code)
+run_cmake(cmake_command_eval_no_parameters)
+run_cmake(cmake_command_eval_variable_outside_message)

+ 1 - 0
Tests/RunCMake/cmake_command/cmake_command_eval_message-stderr.txt

@@ -0,0 +1 @@
+WORKS!

+ 1 - 0
Tests/RunCMake/cmake_command/cmake_command_eval_message.cmake

@@ -0,0 +1 @@
+cmake_command(EVAL CODE message(WORKS!))

+ 1 - 0
Tests/RunCMake/cmake_command/cmake_command_eval_message_fatal_error-result.txt

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

+ 5 - 0
Tests/RunCMake/cmake_command/cmake_command_eval_message_fatal_error-stderr.txt

@@ -0,0 +1,5 @@
+CMake Error at cmake_command_eval_message_fatal_error.cmake:1:EVAL:2 \(message\):
+  error!
+Call Stack \(most recent call first\):
+  cmake_command_eval_message_fatal_error.cmake:1 \(cmake_command\)
+  CMakeLists.txt:3 \(include\)

+ 5 - 0
Tests/RunCMake/cmake_command/cmake_command_eval_message_fatal_error.cmake

@@ -0,0 +1,5 @@
+cmake_command(EVAL CODE
+"
+  message(FATAL_ERROR error!)
+"
+)

+ 1 - 0
Tests/RunCMake/cmake_command/cmake_command_eval_no_code-result.txt

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

+ 2 - 0
Tests/RunCMake/cmake_command/cmake_command_eval_no_code-stderr.txt

@@ -0,0 +1,2 @@
+CMake Error at cmake_command_eval_no_code.cmake:1 \(cmake_command\):
+  cmake_command called without CODE argument

+ 1 - 0
Tests/RunCMake/cmake_command/cmake_command_eval_no_code.cmake

@@ -0,0 +1 @@
+cmake_command(EVAL message "too many parameters")

+ 1 - 0
Tests/RunCMake/cmake_command/cmake_command_eval_no_parameters-result.txt

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

+ 2 - 0
Tests/RunCMake/cmake_command/cmake_command_eval_no_parameters-stderr.txt

@@ -0,0 +1,2 @@
+CMake Error at cmake_command_eval_no_parameters.cmake:1 \(cmake_command\):
+  cmake_command called with incorrect number of arguments

+ 1 - 0
Tests/RunCMake/cmake_command/cmake_command_eval_no_parameters.cmake

@@ -0,0 +1 @@
+cmake_command(EVAL)

+ 1 - 0
Tests/RunCMake/cmake_command/cmake_command_eval_variable_outside_message-stderr.txt

@@ -0,0 +1 @@
+WORKS!

+ 2 - 0
Tests/RunCMake/cmake_command/cmake_command_eval_variable_outside_message.cmake

@@ -0,0 +1,2 @@
+cmake_command(EVAL CODE "set(phrase \"WORKS!\")")
+message(${phrase})