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

This commit is contained in:
Cristian Adam
2020-02-27 20:20:22 +01:00
committed by Brad King
parent c58b9c5ab9
commit 598b676b5e
24 changed files with 183 additions and 37 deletions
+52 -2
View File
@@ -9,6 +9,7 @@ Synopsis
.. parsed-literal:: .. parsed-literal::
cmake_command(`INVOKE`_ <command> [<args>...]) cmake_command(`INVOKE`_ <command> [<args>...])
cmake_command(`EVAL`_ CODE <code>...)
Introduction Introduction
^^^^^^^^^^^^ ^^^^^^^^^^^^
@@ -16,8 +17,10 @@ Introduction
This command will call meta-operations on built-in CMake commands or This command will call meta-operations on built-in CMake commands or
those created via the :command:`macro` or :command:`function` commands. 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: .. _INVOKE:
@@ -38,3 +41,50 @@ is equivalent to
.. code-block:: cmake .. code-block:: cmake
message(STATUS "Hello World!") 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
View File
@@ -3,4 +3,4 @@ cmake_command
* The :command:`cmake_command()` command was added for meta-operations on * The :command:`cmake_command()` command was added for meta-operations on
scripted or built-in commands, starting with a mode to ``INVOKE`` other 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
View File
@@ -2787,7 +2787,7 @@ int cmListFileLexer_SetString(cmListFileLexer* lexer, const char* text)
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer) cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer)
{ {
if (!lexer->file) { if (!lexer->file && !lexer->string_buffer) {
return 0; return 0;
} }
if (cmListFileLexer_yylex(lexer->scanner, lexer)) { if (cmListFileLexer_yylex(lexer->scanner, lexer)) {
@@ -2801,21 +2801,13 @@ cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer)
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
long cmListFileLexer_GetCurrentLine(cmListFileLexer* lexer) long cmListFileLexer_GetCurrentLine(cmListFileLexer* lexer)
{ {
if (lexer->file) { return lexer->line;
return lexer->line;
} else {
return 0;
}
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
long cmListFileLexer_GetCurrentColumn(cmListFileLexer* lexer) long cmListFileLexer_GetCurrentColumn(cmListFileLexer* lexer)
{ {
if (lexer->file) { return lexer->column;
return lexer->column;
} else {
return 0;
}
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
+3 -11
View File
@@ -500,7 +500,7 @@ int cmListFileLexer_SetString(cmListFileLexer* lexer, const char* text)
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer) cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer)
{ {
if (!lexer->file) { if (!lexer->file && !lexer->string_buffer) {
return 0; return 0;
} }
if (cmListFileLexer_yylex(lexer->scanner, lexer)) { if (cmListFileLexer_yylex(lexer->scanner, lexer)) {
@@ -514,21 +514,13 @@ cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer)
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
long cmListFileLexer_GetCurrentLine(cmListFileLexer* lexer) long cmListFileLexer_GetCurrentLine(cmListFileLexer* lexer)
{ {
if (lexer->file) { return lexer->line;
return lexer->line;
} else {
return 0;
}
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
long cmListFileLexer_GetCurrentColumn(cmListFileLexer* lexer) long cmListFileLexer_GetCurrentColumn(cmListFileLexer* lexer)
{ {
if (lexer->file) { return lexer->column;
return lexer->column;
} else {
return 0;
}
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
+24 -3
View File
@@ -2,11 +2,14 @@
file Copyright.txt or https://cmake.org/licensing for details. */ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCMakeCommand.h" #include "cmCMakeCommand.h"
#include <algorithm>
#include <cstddef> #include <cstddef>
#include "cmExecutionStatus.h" #include "cmExecutionStatus.h"
#include "cmListFileCache.h" #include "cmListFileCache.h"
#include "cmMakefile.h" #include "cmMakefile.h"
#include "cmRange.h"
#include "cmStringAlgorithms.h"
bool cmCMakeCommand(std::vector<std::string> const& args, bool cmCMakeCommand(std::vector<std::string> const& args,
cmExecutionStatus& status) cmExecutionStatus& status)
@@ -19,6 +22,8 @@ bool cmCMakeCommand(std::vector<std::string> const& args,
cmMakefile& makefile = status.GetMakefile(); cmMakefile& makefile = status.GetMakefile();
cmListFileContext context = makefile.GetExecutionContext(); cmListFileContext context = makefile.GetExecutionContext();
bool result = false;
if (args[0] == "INVOKE") { if (args[0] == "INVOKE") {
if (args.size() == 1) { if (args.size() == 1) {
status.SetError("called with incorrect number of arguments"); 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); 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 result;
return false;
} }
+43 -8
View File
@@ -26,13 +26,15 @@ cmCommandContext::cmCommandName& cmCommandContext::cmCommandName::operator=(
struct cmListFileParser struct cmListFileParser
{ {
cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt, cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt,
cmMessenger* messenger, const char* filename); cmMessenger* messenger);
~cmListFileParser(); ~cmListFileParser();
cmListFileParser(const cmListFileParser&) = delete; cmListFileParser(const cmListFileParser&) = delete;
cmListFileParser& operator=(const cmListFileParser&) = delete; cmListFileParser& operator=(const cmListFileParser&) = delete;
void IssueFileOpenError(std::string const& text) const; void IssueFileOpenError(std::string const& text) const;
void IssueError(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 ParseFunction(const char* name, long line);
bool AddArgument(cmListFileLexer_Token* token, bool AddArgument(cmListFileLexer_Token* token,
cmListFileArgument::Delimiter delim); cmListFileArgument::Delimiter delim);
@@ -51,12 +53,11 @@ struct cmListFileParser
}; };
cmListFileParser::cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt, cmListFileParser::cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt,
cmMessenger* messenger, cmMessenger* messenger)
const char* filename)
: ListFile(lf) : ListFile(lf)
, Backtrace(std::move(lfbt)) , Backtrace(std::move(lfbt))
, Messenger(messenger) , Messenger(messenger)
, FileName(filename) , FileName(nullptr)
, Lexer(cmListFileLexer_New()) , Lexer(cmListFileLexer_New())
{ {
} }
@@ -83,8 +84,10 @@ void cmListFileParser::IssueError(const std::string& text) const
cmSystemTools::SetFatalErrorOccured(); cmSystemTools::SetFatalErrorOccured();
} }
bool cmListFileParser::ParseFile() bool cmListFileParser::ParseFile(const char* filename)
{ {
this->FileName = filename;
// Open the file. // Open the file.
cmListFileLexer_BOM bom; cmListFileLexer_BOM bom;
if (!cmListFileLexer_SetFileName(this->Lexer, this->FileName, &bom)) { if (!cmListFileLexer_SetFileName(this->Lexer, this->FileName, &bom)) {
@@ -107,6 +110,24 @@ bool cmListFileParser::ParseFile()
return false; 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 // Use a simple recursive-descent parser to process the token
// stream. // stream.
bool haveNewline = true; bool haveNewline = true;
@@ -155,8 +176,22 @@ bool cmListFile::ParseFile(const char* filename, cmMessenger* messenger,
bool parseError = false; bool parseError = false;
{ {
cmListFileParser parser(this, lfbt, messenger, filename); cmListFileParser parser(this, lfbt, messenger);
parseError = !parser.ParseFile(); 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; return !parseError;
+3
View File
@@ -184,6 +184,9 @@ struct cmListFile
bool ParseFile(const char* path, cmMessenger* messenger, bool ParseFile(const char* path, cmMessenger* messenger,
cmListFileBacktrace const& lfbt); cmListFileBacktrace const& lfbt);
bool ParseString(const char* str, const char* virtual_filename,
cmMessenger* messenger, cmListFileBacktrace const& lfbt);
std::vector<cmListFileFunction> Functions; std::vector<cmListFileFunction> Functions;
}; };
+21
View File
@@ -684,6 +684,27 @@ bool cmMakefile::ReadListFile(const std::string& filename)
return true; 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, void cmMakefile::ReadListFile(cmListFile const& listFile,
std::string const& filenametoread) std::string const& filenametoread)
{ {
+3
View File
@@ -117,6 +117,9 @@ public:
bool ReadListFile(const std::string& filename); bool ReadListFile(const std::string& filename);
bool ReadListFileAsString(const std::string& content,
const std::string& virtualFileName);
bool ReadDependentFile(const std::string& filename, bool ReadDependentFile(const std::string& filename,
bool noPolicyScope = true); bool noPolicyScope = true);
+1 -1
View File
@@ -1,4 +1,4 @@
^CMake Error in CommandEOF.cmake: ^CMake Error at CommandEOF.cmake:1:
Unexpected end of file. Unexpected end of file.
Parse error. Function missing opening "\(". Parse error. Function missing opening "\(".
@@ -6,3 +6,8 @@ run_cmake(cmake_command_invoke_message)
run_cmake(cmake_command_invoke_message_fatal_error) run_cmake(cmake_command_invoke_message_fatal_error)
run_cmake(cmake_command_invoke_no_parameters) run_cmake(cmake_command_invoke_no_parameters)
run_cmake(cmake_command_invoke_unknown_function) 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)
@@ -0,0 +1 @@
WORKS!
@@ -0,0 +1 @@
cmake_command(EVAL CODE message(WORKS!))
@@ -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\)
@@ -0,0 +1,5 @@
cmake_command(EVAL CODE
"
message(FATAL_ERROR error!)
"
)
@@ -0,0 +1,2 @@
CMake Error at cmake_command_eval_no_code.cmake:1 \(cmake_command\):
cmake_command called without CODE argument
@@ -0,0 +1 @@
cmake_command(EVAL message "too many parameters")
@@ -0,0 +1,2 @@
CMake Error at cmake_command_eval_no_parameters.cmake:1 \(cmake_command\):
cmake_command called with incorrect number of arguments
@@ -0,0 +1 @@
cmake_command(EVAL)
@@ -0,0 +1,2 @@
cmake_command(EVAL CODE "set(phrase \"WORKS!\")")
message(${phrase})