summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCristian Adam <cristian.adam@gmail.com>2020-02-27 20:20:22 +0100
committerBrad King <brad.king@kitware.com>2020-03-03 08:42:13 -0500
commit598b676b5e77540b366b01b3c10154c2a633d23c (patch)
treeeb3aaea48e3c1743835a74be111ca64ee4a9a4e5
parentc58b9c5ab94d674c76a17e6154f05e0e8c5c37d1 (diff)
downloadcmake-598b676b5e77540b366b01b3c10154c2a633d23c.tar.gz
cmake_command: Add command to EVAL a CMake script as a string
-rw-r--r--Help/command/cmake_command.rst54
-rw-r--r--Help/release/dev/cmake_command-command.rst2
-rw-r--r--Source/LexerParser/cmListFileLexer.c14
-rw-r--r--Source/LexerParser/cmListFileLexer.in.l14
-rw-r--r--Source/cmCMakeCommand.cxx27
-rw-r--r--Source/cmListFileCache.cxx51
-rw-r--r--Source/cmListFileCache.h3
-rw-r--r--Source/cmMakefile.cxx21
-rw-r--r--Source/cmMakefile.h3
-rw-r--r--Tests/RunCMake/Syntax/CommandEOF-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_command/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/cmake_command/cmake_command_eval_message-stderr.txt1
-rw-r--r--Tests/RunCMake/cmake_command/cmake_command_eval_message.cmake1
-rw-r--r--Tests/RunCMake/cmake_command/cmake_command_eval_message_fatal_error-result.txt1
-rw-r--r--Tests/RunCMake/cmake_command/cmake_command_eval_message_fatal_error-stderr.txt5
-rw-r--r--Tests/RunCMake/cmake_command/cmake_command_eval_message_fatal_error.cmake5
-rw-r--r--Tests/RunCMake/cmake_command/cmake_command_eval_no_code-result.txt1
-rw-r--r--Tests/RunCMake/cmake_command/cmake_command_eval_no_code-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_command/cmake_command_eval_no_code.cmake1
-rw-r--r--Tests/RunCMake/cmake_command/cmake_command_eval_no_parameters-result.txt1
-rw-r--r--Tests/RunCMake/cmake_command/cmake_command_eval_no_parameters-stderr.txt2
-rw-r--r--Tests/RunCMake/cmake_command/cmake_command_eval_no_parameters.cmake1
-rw-r--r--Tests/RunCMake/cmake_command/cmake_command_eval_variable_outside_message-stderr.txt1
-rw-r--r--Tests/RunCMake/cmake_command/cmake_command_eval_variable_outside_message.cmake2
24 files changed, 183 insertions, 37 deletions
diff --git a/Help/command/cmake_command.rst b/Help/command/cmake_command.rst
index 92816474bb..08b783232d 100644
--- a/Help/command/cmake_command.rst
+++ b/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)
diff --git a/Help/release/dev/cmake_command-command.rst b/Help/release/dev/cmake_command-command.rst
index ebe75b1e23..6200ae20e3 100644
--- a/Help/release/dev/cmake_command-command.rst
+++ b/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.
diff --git a/Source/LexerParser/cmListFileLexer.c b/Source/LexerParser/cmListFileLexer.c
index 15dcda04a0..ec7424c4f9 100644
--- a/Source/LexerParser/cmListFileLexer.c
+++ b/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;
}
/*--------------------------------------------------------------------------*/
diff --git a/Source/LexerParser/cmListFileLexer.in.l b/Source/LexerParser/cmListFileLexer.in.l
index fdf14d2d38..94cf8a5943 100644
--- a/Source/LexerParser/cmListFileLexer.in.l
+++ b/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;
}
/*--------------------------------------------------------------------------*/
diff --git a/Source/cmCMakeCommand.cxx b/Source/cmCMakeCommand.cxx
index 56990864b0..c11a00364c 100644
--- a/Source/cmCMakeCommand.cxx
+++ b/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;
}
diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx
index 47679c9322..7ebb02f492 100644
--- a/Source/cmListFileCache.cxx
+++ b/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;
diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h
index 9cae8277b2..89902ff30b 100644
--- a/Source/cmListFileCache.h
+++ b/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;
};
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index ed627f8e72..94d99b7a4a 100644
--- a/Source/cmMakefile.cxx
+++ b/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)
{
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index f1a68c2902..9c6dca62db 100644
--- a/Source/cmMakefile.h
+++ b/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);
diff --git a/Tests/RunCMake/Syntax/CommandEOF-stderr.txt b/Tests/RunCMake/Syntax/CommandEOF-stderr.txt
index 31cbc08d71..b9f8fd1eeb 100644
--- a/Tests/RunCMake/Syntax/CommandEOF-stderr.txt
+++ b/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 "\(".
diff --git a/Tests/RunCMake/cmake_command/RunCMakeTest.cmake b/Tests/RunCMake/cmake_command/RunCMakeTest.cmake
index d338cd8fa7..2b6e7a2793 100644
--- a/Tests/RunCMake/cmake_command/RunCMakeTest.cmake
+++ b/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)
diff --git a/Tests/RunCMake/cmake_command/cmake_command_eval_message-stderr.txt b/Tests/RunCMake/cmake_command/cmake_command_eval_message-stderr.txt
new file mode 100644
index 0000000000..cfc8694cfb
--- /dev/null
+++ b/Tests/RunCMake/cmake_command/cmake_command_eval_message-stderr.txt
@@ -0,0 +1 @@
+WORKS!
diff --git a/Tests/RunCMake/cmake_command/cmake_command_eval_message.cmake b/Tests/RunCMake/cmake_command/cmake_command_eval_message.cmake
new file mode 100644
index 0000000000..9ef5e25daf
--- /dev/null
+++ b/Tests/RunCMake/cmake_command/cmake_command_eval_message.cmake
@@ -0,0 +1 @@
+cmake_command(EVAL CODE message(WORKS!))
diff --git a/Tests/RunCMake/cmake_command/cmake_command_eval_message_fatal_error-result.txt b/Tests/RunCMake/cmake_command/cmake_command_eval_message_fatal_error-result.txt
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/Tests/RunCMake/cmake_command/cmake_command_eval_message_fatal_error-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_command/cmake_command_eval_message_fatal_error-stderr.txt b/Tests/RunCMake/cmake_command/cmake_command_eval_message_fatal_error-stderr.txt
new file mode 100644
index 0000000000..6a8a124592
--- /dev/null
+++ b/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\)
diff --git a/Tests/RunCMake/cmake_command/cmake_command_eval_message_fatal_error.cmake b/Tests/RunCMake/cmake_command/cmake_command_eval_message_fatal_error.cmake
new file mode 100644
index 0000000000..22913de41a
--- /dev/null
+++ b/Tests/RunCMake/cmake_command/cmake_command_eval_message_fatal_error.cmake
@@ -0,0 +1,5 @@
+cmake_command(EVAL CODE
+"
+ message(FATAL_ERROR error!)
+"
+)
diff --git a/Tests/RunCMake/cmake_command/cmake_command_eval_no_code-result.txt b/Tests/RunCMake/cmake_command/cmake_command_eval_no_code-result.txt
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/Tests/RunCMake/cmake_command/cmake_command_eval_no_code-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_command/cmake_command_eval_no_code-stderr.txt b/Tests/RunCMake/cmake_command/cmake_command_eval_no_code-stderr.txt
new file mode 100644
index 0000000000..ee53312ecf
--- /dev/null
+++ b/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
diff --git a/Tests/RunCMake/cmake_command/cmake_command_eval_no_code.cmake b/Tests/RunCMake/cmake_command/cmake_command_eval_no_code.cmake
new file mode 100644
index 0000000000..22e166753d
--- /dev/null
+++ b/Tests/RunCMake/cmake_command/cmake_command_eval_no_code.cmake
@@ -0,0 +1 @@
+cmake_command(EVAL message "too many parameters")
diff --git a/Tests/RunCMake/cmake_command/cmake_command_eval_no_parameters-result.txt b/Tests/RunCMake/cmake_command/cmake_command_eval_no_parameters-result.txt
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/Tests/RunCMake/cmake_command/cmake_command_eval_no_parameters-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_command/cmake_command_eval_no_parameters-stderr.txt b/Tests/RunCMake/cmake_command/cmake_command_eval_no_parameters-stderr.txt
new file mode 100644
index 0000000000..e9fc317e59
--- /dev/null
+++ b/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
diff --git a/Tests/RunCMake/cmake_command/cmake_command_eval_no_parameters.cmake b/Tests/RunCMake/cmake_command/cmake_command_eval_no_parameters.cmake
new file mode 100644
index 0000000000..a5ba2c7d98
--- /dev/null
+++ b/Tests/RunCMake/cmake_command/cmake_command_eval_no_parameters.cmake
@@ -0,0 +1 @@
+cmake_command(EVAL)
diff --git a/Tests/RunCMake/cmake_command/cmake_command_eval_variable_outside_message-stderr.txt b/Tests/RunCMake/cmake_command/cmake_command_eval_variable_outside_message-stderr.txt
new file mode 100644
index 0000000000..cfc8694cfb
--- /dev/null
+++ b/Tests/RunCMake/cmake_command/cmake_command_eval_variable_outside_message-stderr.txt
@@ -0,0 +1 @@
+WORKS!
diff --git a/Tests/RunCMake/cmake_command/cmake_command_eval_variable_outside_message.cmake b/Tests/RunCMake/cmake_command/cmake_command_eval_variable_outside_message.cmake
new file mode 100644
index 0000000000..b7a06a518b
--- /dev/null
+++ b/Tests/RunCMake/cmake_command/cmake_command_eval_variable_outside_message.cmake
@@ -0,0 +1,2 @@
+cmake_command(EVAL CODE "set(phrase \"WORKS!\")")
+message(${phrase})