mirror of
https://github.com/Kitware/CMake.git
synced 2026-05-04 13:19:51 -05:00
cmake_command: Add command to EVAL a CMake script as a string
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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,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 @@
|
|||||||
|
1
|
||||||
@@ -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 @@
|
|||||||
|
1
|
||||||
@@ -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 @@
|
|||||||
|
1
|
||||||
@@ -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 @@
|
|||||||
|
WORKS!
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
cmake_command(EVAL CODE "set(phrase \"WORKS!\")")
|
||||||
|
message(${phrase})
|
||||||
Reference in New Issue
Block a user