Merge topic 'generator-expression-refactor'
91011bd cmGeneratorExpression: Port users to two-stage processing f1eacf0 cmGeneratorExpression: Re-write for multi-stage evaluation
This commit is contained in:
commit
d407dcdbc8
@ -183,6 +183,12 @@ set(SRCS
|
|||||||
cmFileTimeComparison.cxx
|
cmFileTimeComparison.cxx
|
||||||
cmFileTimeComparison.h
|
cmFileTimeComparison.h
|
||||||
cmGeneratedFileStream.cxx
|
cmGeneratedFileStream.cxx
|
||||||
|
cmGeneratorExpressionEvaluator.cxx
|
||||||
|
cmGeneratorExpressionEvaluator.h
|
||||||
|
cmGeneratorExpressionLexer.cxx
|
||||||
|
cmGeneratorExpressionLexer.h
|
||||||
|
cmGeneratorExpressionParser.cxx
|
||||||
|
cmGeneratorExpressionParser.h
|
||||||
cmGeneratorExpression.cxx
|
cmGeneratorExpression.cxx
|
||||||
cmGeneratorExpression.h
|
cmGeneratorExpression.h
|
||||||
cmGeneratorTarget.cxx
|
cmGeneratorTarget.cxx
|
||||||
|
@ -21,7 +21,7 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(
|
|||||||
cmCustomCommand const& cc, const char* config, cmMakefile* mf):
|
cmCustomCommand const& cc, const char* config, cmMakefile* mf):
|
||||||
CC(cc), Config(config), Makefile(mf), LG(mf->GetLocalGenerator()),
|
CC(cc), Config(config), Makefile(mf), LG(mf->GetLocalGenerator()),
|
||||||
OldStyle(cc.GetEscapeOldStyle()), MakeVars(cc.GetEscapeAllowMakeVars()),
|
OldStyle(cc.GetEscapeOldStyle()), MakeVars(cc.GetEscapeAllowMakeVars()),
|
||||||
GE(new cmGeneratorExpression(mf, config, cc.GetBacktrace()))
|
GE(new cmGeneratorExpression(cc.GetBacktrace()))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const
|
|||||||
{
|
{
|
||||||
return target->GetLocation(this->Config);
|
return target->GetLocation(this->Config);
|
||||||
}
|
}
|
||||||
return this->GE->Process(argv0);
|
return this->GE->Parse(argv0).Evaluate(this->Makefile, this->Config);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -58,7 +58,8 @@ cmCustomCommandGenerator
|
|||||||
cmCustomCommandLine const& commandLine = this->CC.GetCommandLines()[c];
|
cmCustomCommandLine const& commandLine = this->CC.GetCommandLines()[c];
|
||||||
for(unsigned int j=1;j < commandLine.size(); ++j)
|
for(unsigned int j=1;j < commandLine.size(); ++j)
|
||||||
{
|
{
|
||||||
std::string arg = this->GE->Process(commandLine[j]);
|
std::string arg = this->GE->Parse(commandLine[j]).Evaluate(this->Makefile,
|
||||||
|
this->Config);
|
||||||
cmd += " ";
|
cmd += " ";
|
||||||
if(this->OldStyle)
|
if(this->OldStyle)
|
||||||
{
|
{
|
||||||
|
@ -16,233 +16,112 @@
|
|||||||
|
|
||||||
#include <cmsys/String.h>
|
#include <cmsys/String.h>
|
||||||
|
|
||||||
|
#include "cmGeneratorExpressionEvaluator.h"
|
||||||
|
#include "cmGeneratorExpressionLexer.h"
|
||||||
|
#include "cmGeneratorExpressionParser.h"
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
cmGeneratorExpression::cmGeneratorExpression(
|
cmGeneratorExpression::cmGeneratorExpression(
|
||||||
cmMakefile* mf, const char* config,
|
cmListFileBacktrace const& backtrace):
|
||||||
cmListFileBacktrace const& backtrace, bool quiet):
|
Backtrace(backtrace), CompiledExpression(0)
|
||||||
Makefile(mf), Config(config), Backtrace(backtrace), Quiet(quiet)
|
|
||||||
{
|
{
|
||||||
this->TargetInfo.compile("^\\$<TARGET"
|
|
||||||
"(|_SONAME|_LINKER)" // File with what purpose?
|
|
||||||
"_FILE(|_NAME|_DIR):" // Filename component.
|
|
||||||
"([A-Za-z0-9_.-]+)" // Target name.
|
|
||||||
">$");
|
|
||||||
this->TestConfig.compile("^\\$<CONFIG:([A-Za-z0-9_]*)>$");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
const char* cmGeneratorExpression::Process(std::string const& input)
|
const cmCompiledGeneratorExpression &
|
||||||
|
cmGeneratorExpression::Parse(std::string const& input)
|
||||||
{
|
{
|
||||||
return this->Process(input.c_str());
|
return this->Parse(input.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
const char* cmGeneratorExpression::Process(const char* input)
|
const cmCompiledGeneratorExpression &
|
||||||
|
cmGeneratorExpression::Parse(const char* input)
|
||||||
{
|
{
|
||||||
this->Data.clear();
|
cmGeneratorExpressionLexer l;
|
||||||
|
std::vector<cmGeneratorExpressionToken> tokens = l.Tokenize(input);
|
||||||
|
bool needsParsing = l.GetSawGeneratorExpression();
|
||||||
|
std::vector<cmGeneratorExpressionEvaluator*> evaluators;
|
||||||
|
|
||||||
// We construct and evaluate expressions directly in the output
|
if (needsParsing)
|
||||||
// buffer. Each expression is replaced by its own output value
|
|
||||||
// after evaluation. A stack of barriers records the starting
|
|
||||||
// indices of open (pending) expressions.
|
|
||||||
for(const char* c = input; *c; ++c)
|
|
||||||
{
|
{
|
||||||
if(c[0] == '$' && c[1] == '<')
|
cmGeneratorExpressionParser p(tokens);
|
||||||
{
|
p.Parse(evaluators);
|
||||||
this->Barriers.push(this->Data.size());
|
|
||||||
this->Data.push_back('$');
|
|
||||||
this->Data.push_back('<');
|
|
||||||
c += 1;
|
|
||||||
}
|
|
||||||
else if(c[0] == '>' && !this->Barriers.empty())
|
|
||||||
{
|
|
||||||
this->Data.push_back('>');
|
|
||||||
if(!this->Evaluate()) { break; }
|
|
||||||
this->Barriers.pop();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->Data.push_back(c[0]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a null-terminated output value.
|
delete this->CompiledExpression;
|
||||||
this->Data.push_back('\0');
|
this->CompiledExpression = new cmCompiledGeneratorExpression(
|
||||||
return &*this->Data.begin();
|
this->Backtrace,
|
||||||
|
evaluators,
|
||||||
|
input,
|
||||||
|
needsParsing);
|
||||||
|
return *this->CompiledExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmGeneratorExpression::~cmGeneratorExpression()
|
||||||
|
{
|
||||||
|
delete this->CompiledExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
bool cmGeneratorExpression::Evaluate()
|
const char *cmCompiledGeneratorExpression::Evaluate(
|
||||||
|
cmMakefile* mf, const char* config, bool quiet) const
|
||||||
{
|
{
|
||||||
// The top-most barrier points at the beginning of the expression.
|
if (!this->NeedsParsing)
|
||||||
size_t barrier = this->Barriers.top();
|
|
||||||
|
|
||||||
// Construct a null-terminated representation of the expression.
|
|
||||||
this->Data.push_back('\0');
|
|
||||||
const char* expr = &*(this->Data.begin()+barrier);
|
|
||||||
|
|
||||||
// Evaluate the expression.
|
|
||||||
std::string result;
|
|
||||||
if(this->Evaluate(expr, result))
|
|
||||||
{
|
{
|
||||||
// Success. Replace the expression with its evaluation result.
|
return this->Input;
|
||||||
this->Data.erase(this->Data.begin()+barrier, this->Data.end());
|
|
||||||
this->Data.insert(this->Data.end(), result.begin(), result.end());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else if(!this->Quiet)
|
|
||||||
|
this->Output = "";
|
||||||
|
|
||||||
|
std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
|
||||||
|
= this->Evaluators.begin();
|
||||||
|
const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
|
||||||
|
= this->Evaluators.end();
|
||||||
|
|
||||||
|
cmGeneratorExpressionContext context;
|
||||||
|
context.Makefile = mf;
|
||||||
|
context.Config = config;
|
||||||
|
context.Quiet = quiet;
|
||||||
|
context.HadError = false;
|
||||||
|
context.Backtrace = this->Backtrace;
|
||||||
|
|
||||||
|
for ( ; it != end; ++it)
|
||||||
{
|
{
|
||||||
// Failure. Report the error message.
|
this->Output += (*it)->Evaluate(&context);
|
||||||
cmOStringStream e;
|
if (context.HadError)
|
||||||
e << "Error evaluating generator expression:\n"
|
{
|
||||||
<< " " << expr << "\n"
|
this->Output = "";
|
||||||
<< result;
|
break;
|
||||||
this->Makefile->GetCMakeInstance()
|
}
|
||||||
->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
|
|
||||||
this->Backtrace);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
this->Targets = context.Targets;
|
||||||
|
// TODO: Return a std::string from here instead?
|
||||||
|
return this->Output.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmCompiledGeneratorExpression::cmCompiledGeneratorExpression(
|
||||||
|
cmListFileBacktrace const& backtrace,
|
||||||
|
const std::vector<cmGeneratorExpressionEvaluator*> &evaluators,
|
||||||
|
const char *input, bool needsParsing)
|
||||||
|
: Backtrace(backtrace), Evaluators(evaluators), Input(input),
|
||||||
|
NeedsParsing(needsParsing)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
static bool cmGeneratorExpressionBool(const char* c, std::string& result,
|
cmCompiledGeneratorExpression::~cmCompiledGeneratorExpression()
|
||||||
const char* name,
|
|
||||||
const char* a, const char* b)
|
|
||||||
{
|
{
|
||||||
result = a;
|
std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
|
||||||
while((c[0] == '0' || c[0] == '1') && (c[1] == ',' || c[1] == '>'))
|
= this->Evaluators.begin();
|
||||||
|
const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
|
||||||
|
= this->Evaluators.end();
|
||||||
|
|
||||||
|
for ( ; it != end; ++it)
|
||||||
{
|
{
|
||||||
if(c[0] == b[0]) { result = b; }
|
delete *it;
|
||||||
c += 2;
|
|
||||||
}
|
}
|
||||||
if(c[0])
|
|
||||||
{
|
|
||||||
result = name;
|
|
||||||
result += " requires one or more comma-separated '0' or '1' values.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool cmGeneratorExpression::Evaluate(const char* expr, std::string& result)
|
|
||||||
{
|
|
||||||
if(this->TargetInfo.find(expr))
|
|
||||||
{
|
|
||||||
if(!this->EvaluateTargetInfo(result))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(strcmp(expr, "$<CONFIGURATION>") == 0)
|
|
||||||
{
|
|
||||||
result = this->Config? this->Config : "";
|
|
||||||
}
|
|
||||||
else if(strncmp(expr, "$<0:",4) == 0)
|
|
||||||
{
|
|
||||||
result = "";
|
|
||||||
}
|
|
||||||
else if(strncmp(expr, "$<1:",4) == 0)
|
|
||||||
{
|
|
||||||
result = std::string(expr+4, strlen(expr)-5);
|
|
||||||
}
|
|
||||||
else if(strncmp(expr, "$<NOT:",6) == 0)
|
|
||||||
{
|
|
||||||
const char* c = expr+6;
|
|
||||||
if((c[0] != '0' && c[0] != '1') || c[1] != '>' || c[2])
|
|
||||||
{
|
|
||||||
result = "NOT requires exactly one '0' or '1' value.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
result = c[0] == '1'? "0" : "1";
|
|
||||||
}
|
|
||||||
else if(strncmp(expr, "$<AND:",6) == 0)
|
|
||||||
{
|
|
||||||
return cmGeneratorExpressionBool(expr+6, result, "AND", "1", "0");
|
|
||||||
}
|
|
||||||
else if(strncmp(expr, "$<OR:",5) == 0)
|
|
||||||
{
|
|
||||||
return cmGeneratorExpressionBool(expr+5, result, "OR", "0", "1");
|
|
||||||
}
|
|
||||||
else if(this->TestConfig.find(expr))
|
|
||||||
{
|
|
||||||
result = cmsysString_strcasecmp(this->TestConfig.match(1).c_str(),
|
|
||||||
this->Config? this->Config:"") == 0
|
|
||||||
? "1":"0";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = "Expression syntax not recognized.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool cmGeneratorExpression::EvaluateTargetInfo(std::string& result)
|
|
||||||
{
|
|
||||||
// Lookup the referenced target.
|
|
||||||
std::string name = this->TargetInfo.match(3);
|
|
||||||
cmTarget* target = this->Makefile->FindTargetToUse(name.c_str());
|
|
||||||
if(!target)
|
|
||||||
{
|
|
||||||
result = "No target \"" + name + "\"";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(target->GetType() >= cmTarget::UTILITY &&
|
|
||||||
target->GetType() != cmTarget::UNKNOWN_LIBRARY)
|
|
||||||
{
|
|
||||||
result = "Target \"" + name + "\" is not an executable or library.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
this->Targets.insert(target);
|
|
||||||
|
|
||||||
// Lookup the target file with the given purpose.
|
|
||||||
std::string purpose = this->TargetInfo.match(1);
|
|
||||||
if(purpose == "")
|
|
||||||
{
|
|
||||||
// The target implementation file (.so.1.2, .dll, .exe, .a).
|
|
||||||
result = target->GetFullPath(this->Config, false, true);
|
|
||||||
}
|
|
||||||
else if(purpose == "_LINKER")
|
|
||||||
{
|
|
||||||
// The file used to link to the target (.so, .lib, .a).
|
|
||||||
if(!target->IsLinkable())
|
|
||||||
{
|
|
||||||
result = ("TARGET_LINKER_FILE is allowed only for libraries and "
|
|
||||||
"executables with ENABLE_EXPORTS.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
result = target->GetFullPath(this->Config, target->HasImportLibrary());
|
|
||||||
}
|
|
||||||
else if(purpose == "_SONAME")
|
|
||||||
{
|
|
||||||
// The target soname file (.so.1).
|
|
||||||
if(target->IsDLLPlatform())
|
|
||||||
{
|
|
||||||
result = "TARGET_SONAME_FILE is not allowed for DLL target platforms.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(target->GetType() != cmTarget::SHARED_LIBRARY)
|
|
||||||
{
|
|
||||||
result = "TARGET_SONAME_FILE is allowed only for SHARED libraries.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
result = target->GetDirectory(this->Config);
|
|
||||||
result += "/";
|
|
||||||
result += target->GetSOName(this->Config);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract the requested portion of the full path.
|
|
||||||
std::string part = this->TargetInfo.match(2);
|
|
||||||
if(part == "_NAME")
|
|
||||||
{
|
|
||||||
result = cmSystemTools::GetFilenameName(result);
|
|
||||||
}
|
|
||||||
else if(part == "_DIR")
|
|
||||||
{
|
|
||||||
result = cmSystemTools::GetFilenamePath(result);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,10 @@ class cmTarget;
|
|||||||
class cmMakefile;
|
class cmMakefile;
|
||||||
class cmListFileBacktrace;
|
class cmListFileBacktrace;
|
||||||
|
|
||||||
|
struct cmGeneratorExpressionEvaluator;
|
||||||
|
|
||||||
|
class cmCompiledGeneratorExpression;
|
||||||
|
|
||||||
/** \class cmGeneratorExpression
|
/** \class cmGeneratorExpression
|
||||||
* \brief Evaluate generate-time query expression syntax.
|
* \brief Evaluate generate-time query expression syntax.
|
||||||
*
|
*
|
||||||
@ -31,29 +35,48 @@ class cmListFileBacktrace;
|
|||||||
class cmGeneratorExpression
|
class cmGeneratorExpression
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/** Construct with an evaluation context and configuration. */
|
/** Construct. */
|
||||||
cmGeneratorExpression(cmMakefile* mf, const char* config,
|
cmGeneratorExpression(cmListFileBacktrace const& backtrace);
|
||||||
cmListFileBacktrace const& backtrace,
|
~cmGeneratorExpression();
|
||||||
bool quiet = false);
|
|
||||||
|
|
||||||
/** Evaluate generator expressions in a string. */
|
const cmCompiledGeneratorExpression& Parse(std::string const& input);
|
||||||
const char* Process(std::string const& input);
|
const cmCompiledGeneratorExpression& Parse(const char* input);
|
||||||
const char* Process(const char* input);
|
|
||||||
|
private:
|
||||||
|
cmGeneratorExpression(const cmGeneratorExpression &);
|
||||||
|
void operator=(const cmGeneratorExpression &);
|
||||||
|
|
||||||
|
cmListFileBacktrace const& Backtrace;
|
||||||
|
cmCompiledGeneratorExpression *CompiledExpression;
|
||||||
|
};
|
||||||
|
|
||||||
|
class cmCompiledGeneratorExpression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const char* Evaluate(cmMakefile* mf, const char* config,
|
||||||
|
bool quiet = false) const;
|
||||||
|
|
||||||
/** Get set of targets found during evaluations. */
|
/** Get set of targets found during evaluations. */
|
||||||
std::set<cmTarget*> const& GetTargets() const
|
std::set<cmTarget*> const& GetTargets() const
|
||||||
{ return this->Targets; }
|
{ return this->Targets; }
|
||||||
|
|
||||||
|
~cmCompiledGeneratorExpression();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
cmMakefile* Makefile;
|
cmCompiledGeneratorExpression(cmListFileBacktrace const& backtrace,
|
||||||
const char* Config;
|
const std::vector<cmGeneratorExpressionEvaluator*> &evaluators,
|
||||||
|
const char *input, bool needsParsing);
|
||||||
|
|
||||||
|
friend class cmGeneratorExpression;
|
||||||
|
|
||||||
|
cmCompiledGeneratorExpression(const cmCompiledGeneratorExpression &);
|
||||||
|
void operator=(const cmCompiledGeneratorExpression &);
|
||||||
|
|
||||||
cmListFileBacktrace const& Backtrace;
|
cmListFileBacktrace const& Backtrace;
|
||||||
bool Quiet;
|
const std::vector<cmGeneratorExpressionEvaluator*> Evaluators;
|
||||||
std::vector<char> Data;
|
const char* const Input;
|
||||||
std::stack<size_t> Barriers;
|
const bool NeedsParsing;
|
||||||
cmsys::RegularExpression TargetInfo;
|
|
||||||
cmsys::RegularExpression TestConfig;
|
mutable std::set<cmTarget*> Targets;
|
||||||
std::set<cmTarget*> Targets;
|
mutable std::string Output;
|
||||||
bool Evaluate();
|
|
||||||
bool Evaluate(const char* expr, std::string& result);
|
|
||||||
bool EvaluateTargetInfo(std::string& result);
|
|
||||||
};
|
};
|
||||||
|
568
Source/cmGeneratorExpressionEvaluator.cxx
Normal file
568
Source/cmGeneratorExpressionEvaluator.cxx
Normal file
@ -0,0 +1,568 @@
|
|||||||
|
/*============================================================================
|
||||||
|
CMake - Cross Platform Makefile Generator
|
||||||
|
Copyright 2012 Stephen Kelly <steveire@gmail.com>
|
||||||
|
|
||||||
|
Distributed under the OSI-approved BSD License (the "License");
|
||||||
|
see accompanying file Copyright.txt for details.
|
||||||
|
|
||||||
|
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||||
|
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the License for more information.
|
||||||
|
============================================================================*/
|
||||||
|
#include "cmMakefile.h"
|
||||||
|
|
||||||
|
#include "cmGeneratorExpressionEvaluator.h"
|
||||||
|
#include "cmGeneratorExpressionParser.h"
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
static void reportError(cmGeneratorExpressionContext *context,
|
||||||
|
const std::string &expr, const std::string &result)
|
||||||
|
{
|
||||||
|
context->HadError = true;
|
||||||
|
if (context->Quiet)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmOStringStream e;
|
||||||
|
e << "Error evaluating generator expression:\n"
|
||||||
|
<< " " << expr << "\n"
|
||||||
|
<< result;
|
||||||
|
context->Makefile->GetCMakeInstance()
|
||||||
|
->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
|
||||||
|
context->Backtrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
struct cmGeneratorExpressionNode
|
||||||
|
{
|
||||||
|
virtual ~cmGeneratorExpressionNode() {}
|
||||||
|
|
||||||
|
virtual bool GeneratesContent() const { return true; }
|
||||||
|
|
||||||
|
virtual bool AcceptsSingleArbitraryContentParameter() const
|
||||||
|
{ return false; }
|
||||||
|
|
||||||
|
virtual int NumExpectedParameters() const { return 1; }
|
||||||
|
|
||||||
|
virtual std::string Evaluate(const std::vector<std::string> ¶meters,
|
||||||
|
cmGeneratorExpressionContext *context,
|
||||||
|
const GeneratorExpressionContent *content
|
||||||
|
) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
static const struct ZeroNode : public cmGeneratorExpressionNode
|
||||||
|
{
|
||||||
|
ZeroNode() {}
|
||||||
|
|
||||||
|
virtual bool GeneratesContent() const { return false; }
|
||||||
|
|
||||||
|
std::string Evaluate(const std::vector<std::string> &,
|
||||||
|
cmGeneratorExpressionContext *,
|
||||||
|
const GeneratorExpressionContent *) const
|
||||||
|
{
|
||||||
|
// Unreachable
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
} zeroNode;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
static const struct OneNode : public cmGeneratorExpressionNode
|
||||||
|
{
|
||||||
|
OneNode() {}
|
||||||
|
|
||||||
|
virtual bool AcceptsSingleArbitraryContentParameter() const { return true; }
|
||||||
|
|
||||||
|
std::string Evaluate(const std::vector<std::string> &,
|
||||||
|
cmGeneratorExpressionContext *,
|
||||||
|
const GeneratorExpressionContent *) const
|
||||||
|
{
|
||||||
|
// Unreachable
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
} oneNode;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
#define BOOLEAN_OP_NODE(OPNAME, OP, SUCCESS_VALUE, FAILURE_VALUE) \
|
||||||
|
static const struct OP ## Node : public cmGeneratorExpressionNode \
|
||||||
|
{ \
|
||||||
|
OP ## Node () {} \
|
||||||
|
/* We let -1 carry the meaning 'at least one' */ \
|
||||||
|
virtual int NumExpectedParameters() const { return -1; } \
|
||||||
|
\
|
||||||
|
std::string Evaluate(const std::vector<std::string> ¶meters, \
|
||||||
|
cmGeneratorExpressionContext *context, \
|
||||||
|
const GeneratorExpressionContent *content) const \
|
||||||
|
{ \
|
||||||
|
std::vector<std::string>::const_iterator it = parameters.begin(); \
|
||||||
|
const std::vector<std::string>::const_iterator end = parameters.end(); \
|
||||||
|
for ( ; it != end; ++it) \
|
||||||
|
{ \
|
||||||
|
if (*it == #FAILURE_VALUE) \
|
||||||
|
{ \
|
||||||
|
return #FAILURE_VALUE; \
|
||||||
|
} \
|
||||||
|
else if (*it != #SUCCESS_VALUE) \
|
||||||
|
{ \
|
||||||
|
reportError(context, content->GetOriginalExpression(), \
|
||||||
|
"Parameters to $<" #OP "> must resolve to either '0' or '1'."); \
|
||||||
|
return std::string(); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
return #SUCCESS_VALUE; \
|
||||||
|
} \
|
||||||
|
} OPNAME;
|
||||||
|
|
||||||
|
BOOLEAN_OP_NODE(andNode, AND, 1, 0)
|
||||||
|
BOOLEAN_OP_NODE(orNode, OR, 0, 1)
|
||||||
|
|
||||||
|
#undef BOOLEAN_OP_NODE
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
static const struct NotNode : public cmGeneratorExpressionNode
|
||||||
|
{
|
||||||
|
NotNode() {}
|
||||||
|
std::string Evaluate(const std::vector<std::string> ¶meters,
|
||||||
|
cmGeneratorExpressionContext *context,
|
||||||
|
const GeneratorExpressionContent *content) const
|
||||||
|
{
|
||||||
|
if (*parameters.begin() != "0" && *parameters.begin() != "1")
|
||||||
|
{
|
||||||
|
reportError(context, content->GetOriginalExpression(),
|
||||||
|
"$<NOT> parameter must resolve to exactly one '0' or '1' value.");
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
return *parameters.begin() == "0" ? "1" : "0";
|
||||||
|
}
|
||||||
|
} notNode;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
static const struct ConfigurationNode : public cmGeneratorExpressionNode
|
||||||
|
{
|
||||||
|
ConfigurationNode() {}
|
||||||
|
virtual int NumExpectedParameters() const { return 0; }
|
||||||
|
|
||||||
|
std::string Evaluate(const std::vector<std::string> &,
|
||||||
|
cmGeneratorExpressionContext *context,
|
||||||
|
const GeneratorExpressionContent *) const
|
||||||
|
{
|
||||||
|
return context->Config ? context->Config : "";
|
||||||
|
}
|
||||||
|
} configurationNode;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
|
||||||
|
{
|
||||||
|
ConfigurationTestNode() {}
|
||||||
|
|
||||||
|
virtual int NumExpectedParameters() const { return 1; }
|
||||||
|
|
||||||
|
std::string Evaluate(const std::vector<std::string> ¶meters,
|
||||||
|
cmGeneratorExpressionContext *context,
|
||||||
|
const GeneratorExpressionContent *content) const
|
||||||
|
{
|
||||||
|
if (!context->Config)
|
||||||
|
{
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
cmsys::RegularExpression configValidator;
|
||||||
|
configValidator.compile("^[A-Za-z0-9_]*$");
|
||||||
|
if (!configValidator.find(parameters.begin()->c_str()))
|
||||||
|
{
|
||||||
|
reportError(context, content->GetOriginalExpression(),
|
||||||
|
"Expression syntax not recognized.");
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
return *parameters.begin() == context->Config ? "1" : "0";
|
||||||
|
}
|
||||||
|
} configurationTestNode;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
template<bool linker, bool soname>
|
||||||
|
struct TargetFilesystemArtifactResultCreator
|
||||||
|
{
|
||||||
|
static std::string Create(cmTarget* target,
|
||||||
|
cmGeneratorExpressionContext *context,
|
||||||
|
const GeneratorExpressionContent *content);
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
template<>
|
||||||
|
struct TargetFilesystemArtifactResultCreator<false, true>
|
||||||
|
{
|
||||||
|
static std::string Create(cmTarget* target,
|
||||||
|
cmGeneratorExpressionContext *context,
|
||||||
|
const GeneratorExpressionContent *content)
|
||||||
|
{
|
||||||
|
// The target soname file (.so.1).
|
||||||
|
if(target->IsDLLPlatform())
|
||||||
|
{
|
||||||
|
::reportError(context, content->GetOriginalExpression(),
|
||||||
|
"TARGET_SONAME_FILE is not allowed "
|
||||||
|
"for DLL target platforms.");
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
if(target->GetType() != cmTarget::SHARED_LIBRARY)
|
||||||
|
{
|
||||||
|
::reportError(context, content->GetOriginalExpression(),
|
||||||
|
"TARGET_SONAME_FILE is allowed only for "
|
||||||
|
"SHARED libraries.");
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
std::string result = target->GetDirectory(context->Config);
|
||||||
|
result += "/";
|
||||||
|
result += target->GetSOName(context->Config);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
template<>
|
||||||
|
struct TargetFilesystemArtifactResultCreator<true, false>
|
||||||
|
{
|
||||||
|
static std::string Create(cmTarget* target,
|
||||||
|
cmGeneratorExpressionContext *context,
|
||||||
|
const GeneratorExpressionContent *content)
|
||||||
|
{
|
||||||
|
// The file used to link to the target (.so, .lib, .a).
|
||||||
|
if(!target->IsLinkable())
|
||||||
|
{
|
||||||
|
::reportError(context, content->GetOriginalExpression(),
|
||||||
|
"TARGET_LINKER_FILE is allowed only for libraries and "
|
||||||
|
"executables with ENABLE_EXPORTS.");
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
return target->GetFullPath(context->Config,
|
||||||
|
target->HasImportLibrary());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
template<>
|
||||||
|
struct TargetFilesystemArtifactResultCreator<false, false>
|
||||||
|
{
|
||||||
|
static std::string Create(cmTarget* target,
|
||||||
|
cmGeneratorExpressionContext *context,
|
||||||
|
const GeneratorExpressionContent *)
|
||||||
|
{
|
||||||
|
return target->GetFullPath(context->Config, false, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
template<bool dirQual, bool nameQual>
|
||||||
|
struct TargetFilesystemArtifactResultGetter
|
||||||
|
{
|
||||||
|
static std::string Get(const std::string &result);
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
template<>
|
||||||
|
struct TargetFilesystemArtifactResultGetter<false, true>
|
||||||
|
{
|
||||||
|
static std::string Get(const std::string &result)
|
||||||
|
{ return cmSystemTools::GetFilenameName(result); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
template<>
|
||||||
|
struct TargetFilesystemArtifactResultGetter<true, false>
|
||||||
|
{
|
||||||
|
static std::string Get(const std::string &result)
|
||||||
|
{ return cmSystemTools::GetFilenamePath(result); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
template<>
|
||||||
|
struct TargetFilesystemArtifactResultGetter<false, false>
|
||||||
|
{
|
||||||
|
static std::string Get(const std::string &result)
|
||||||
|
{ return result; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
template<bool linker, bool soname, bool dirQual, bool nameQual>
|
||||||
|
struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
|
||||||
|
{
|
||||||
|
TargetFilesystemArtifact() {}
|
||||||
|
|
||||||
|
virtual int NumExpectedParameters() const { return 1; }
|
||||||
|
|
||||||
|
std::string Evaluate(const std::vector<std::string> ¶meters,
|
||||||
|
cmGeneratorExpressionContext *context,
|
||||||
|
const GeneratorExpressionContent *content) const
|
||||||
|
{
|
||||||
|
// Lookup the referenced target.
|
||||||
|
std::string name = *parameters.begin();
|
||||||
|
|
||||||
|
cmsys::RegularExpression targetValidator;
|
||||||
|
targetValidator.compile("^[A-Za-z0-9_]+$");
|
||||||
|
if (!targetValidator.find(name.c_str()))
|
||||||
|
{
|
||||||
|
::reportError(context, content->GetOriginalExpression(),
|
||||||
|
"Expression syntax not recognized.");
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
cmTarget* target = context->Makefile->FindTargetToUse(name.c_str());
|
||||||
|
if(!target)
|
||||||
|
{
|
||||||
|
::reportError(context, content->GetOriginalExpression(),
|
||||||
|
"No target \"" + name + "\"");
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
if(target->GetType() >= cmTarget::UTILITY &&
|
||||||
|
target->GetType() != cmTarget::UNKNOWN_LIBRARY)
|
||||||
|
{
|
||||||
|
::reportError(context, content->GetOriginalExpression(),
|
||||||
|
"Target \"" + name + "\" is not an executable or library.");
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
context->Targets.insert(target);
|
||||||
|
|
||||||
|
std::string result =
|
||||||
|
TargetFilesystemArtifactResultCreator<linker, soname>::Create(
|
||||||
|
target,
|
||||||
|
context,
|
||||||
|
content);
|
||||||
|
if (context->HadError)
|
||||||
|
{
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
return
|
||||||
|
TargetFilesystemArtifactResultGetter<dirQual, nameQual>::Get(result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
static const
|
||||||
|
TargetFilesystemArtifact<false, false, false, false> targetFileNode;
|
||||||
|
static const
|
||||||
|
TargetFilesystemArtifact<true, false, false, false> targetLinkerFileNode;
|
||||||
|
static const
|
||||||
|
TargetFilesystemArtifact<false, true, false, false> targetSoNameFileNode;
|
||||||
|
static const
|
||||||
|
TargetFilesystemArtifact<false, false, false, true> targetFileNameNode;
|
||||||
|
static const
|
||||||
|
TargetFilesystemArtifact<true, false, false, true> targetLinkerFileNameNode;
|
||||||
|
static const
|
||||||
|
TargetFilesystemArtifact<false, true, false, true> targetSoNameFileNameNode;
|
||||||
|
static const
|
||||||
|
TargetFilesystemArtifact<false, false, true, false> targetFileDirNode;
|
||||||
|
static const
|
||||||
|
TargetFilesystemArtifact<true, false, true, false> targetLinkerFileDirNode;
|
||||||
|
static const
|
||||||
|
TargetFilesystemArtifact<false, true, true, false> targetSoNameFileDirNode;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
static const
|
||||||
|
cmGeneratorExpressionNode* GetNode(const std::string &identifier)
|
||||||
|
{
|
||||||
|
if (identifier == "0")
|
||||||
|
return &zeroNode;
|
||||||
|
if (identifier == "1")
|
||||||
|
return &oneNode;
|
||||||
|
if (identifier == "AND")
|
||||||
|
return &andNode;
|
||||||
|
if (identifier == "OR")
|
||||||
|
return &orNode;
|
||||||
|
if (identifier == "NOT")
|
||||||
|
return ¬Node;
|
||||||
|
else if (identifier == "CONFIGURATION")
|
||||||
|
return &configurationNode;
|
||||||
|
else if (identifier == "CONFIG")
|
||||||
|
return &configurationTestNode;
|
||||||
|
else if (identifier == "TARGET_FILE")
|
||||||
|
return &targetFileNode;
|
||||||
|
else if (identifier == "TARGET_LINKER_FILE")
|
||||||
|
return &targetLinkerFileNode;
|
||||||
|
else if (identifier == "TARGET_SONAME_FILE")
|
||||||
|
return &targetSoNameFileNode;
|
||||||
|
else if (identifier == "TARGET_FILE_NAME")
|
||||||
|
return &targetFileNameNode;
|
||||||
|
else if (identifier == "TARGET_LINKER_FILE_NAME")
|
||||||
|
return &targetLinkerFileNameNode;
|
||||||
|
else if (identifier == "TARGET_SONAME_FILE_NAME")
|
||||||
|
return &targetSoNameFileNameNode;
|
||||||
|
else if (identifier == "TARGET_FILE_DIR")
|
||||||
|
return &targetFileDirNode;
|
||||||
|
else if (identifier == "TARGET_LINKER_FILE_DIR")
|
||||||
|
return &targetLinkerFileDirNode;
|
||||||
|
else if (identifier == "TARGET_SONAME_FILE_DIR")
|
||||||
|
return &targetSoNameFileDirNode;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
GeneratorExpressionContent::GeneratorExpressionContent(
|
||||||
|
const char *startContent,
|
||||||
|
unsigned int length)
|
||||||
|
: StartContent(startContent), ContentLength(length)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
std::string GeneratorExpressionContent::GetOriginalExpression() const
|
||||||
|
{
|
||||||
|
return std::string(this->StartContent, this->ContentLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
std::string GeneratorExpressionContent::Evaluate(
|
||||||
|
cmGeneratorExpressionContext *context) const
|
||||||
|
{
|
||||||
|
std::string identifier;
|
||||||
|
{
|
||||||
|
std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
|
||||||
|
= this->IdentifierChildren.begin();
|
||||||
|
const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
|
||||||
|
= this->IdentifierChildren.end();
|
||||||
|
for ( ; it != end; ++it)
|
||||||
|
{
|
||||||
|
identifier += (*it)->Evaluate(context);
|
||||||
|
if (context->HadError)
|
||||||
|
{
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const cmGeneratorExpressionNode *node = GetNode(identifier);
|
||||||
|
|
||||||
|
if (!node)
|
||||||
|
{
|
||||||
|
reportError(context, this->GetOriginalExpression(),
|
||||||
|
"Expression did not evaluate to a known generator expression");
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node->GeneratesContent())
|
||||||
|
{
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->AcceptsSingleArbitraryContentParameter())
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
|
||||||
|
pit = this->ParamChildren.begin();
|
||||||
|
const
|
||||||
|
std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
|
||||||
|
pend = this->ParamChildren.end();
|
||||||
|
for ( ; pit != pend; ++pit)
|
||||||
|
{
|
||||||
|
if (!result.empty())
|
||||||
|
{
|
||||||
|
result += ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
|
||||||
|
= pit->begin();
|
||||||
|
const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
|
||||||
|
= pit->end();
|
||||||
|
for ( ; it != end; ++it)
|
||||||
|
{
|
||||||
|
result += (*it)->Evaluate(context);
|
||||||
|
if (context->HadError)
|
||||||
|
{
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> parameters;
|
||||||
|
{
|
||||||
|
std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
|
||||||
|
pit = this->ParamChildren.begin();
|
||||||
|
const
|
||||||
|
std::vector<std::vector<cmGeneratorExpressionEvaluator*> >::const_iterator
|
||||||
|
pend = this->ParamChildren.end();
|
||||||
|
for ( ; pit != pend; ++pit)
|
||||||
|
{
|
||||||
|
std::string parameter;
|
||||||
|
std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
|
||||||
|
pit->begin();
|
||||||
|
const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
|
||||||
|
pit->end();
|
||||||
|
for ( ; it != end; ++it)
|
||||||
|
{
|
||||||
|
parameter += (*it)->Evaluate(context);
|
||||||
|
if (context->HadError)
|
||||||
|
{
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parameters.push_back(parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int numExpected = node->NumExpectedParameters();
|
||||||
|
if ((numExpected != -1 && (unsigned int)numExpected != parameters.size()))
|
||||||
|
{
|
||||||
|
if (numExpected == 0)
|
||||||
|
{
|
||||||
|
reportError(context, this->GetOriginalExpression(),
|
||||||
|
"$<" + identifier + "> expression requires no parameters.");
|
||||||
|
}
|
||||||
|
else if (numExpected == 1)
|
||||||
|
{
|
||||||
|
reportError(context, this->GetOriginalExpression(),
|
||||||
|
"$<" + identifier + "> expression requires "
|
||||||
|
"exactly one parameter.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmOStringStream e;
|
||||||
|
e << "$<" + identifier + "> expression requires "
|
||||||
|
<< numExpected
|
||||||
|
<< " comma separated parameters, but got "
|
||||||
|
<< parameters.size() << " instead.";
|
||||||
|
reportError(context, this->GetOriginalExpression(), e.str());
|
||||||
|
}
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numExpected == -1 && parameters.empty())
|
||||||
|
{
|
||||||
|
reportError(context, this->GetOriginalExpression(), "$<" + identifier
|
||||||
|
+ "> expression requires at least one parameter.");
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
return node->Evaluate(parameters, context, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
static void deleteAll(const std::vector<cmGeneratorExpressionEvaluator*> &c)
|
||||||
|
{
|
||||||
|
std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it
|
||||||
|
= c.begin();
|
||||||
|
const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end
|
||||||
|
= c.end();
|
||||||
|
for ( ; it != end; ++it)
|
||||||
|
{
|
||||||
|
delete *it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
GeneratorExpressionContent::~GeneratorExpressionContent()
|
||||||
|
{
|
||||||
|
deleteAll(this->IdentifierChildren);
|
||||||
|
|
||||||
|
typedef std::vector<cmGeneratorExpressionEvaluator*> EvaluatorVector;
|
||||||
|
typedef std::vector<cmGeneratorExpressionToken> TokenVector;
|
||||||
|
std::vector<EvaluatorVector>::const_iterator pit =
|
||||||
|
this->ParamChildren.begin();
|
||||||
|
const std::vector<EvaluatorVector>::const_iterator pend =
|
||||||
|
this->ParamChildren.end();
|
||||||
|
for ( ; pit != pend; ++pit)
|
||||||
|
{
|
||||||
|
deleteAll(*pit);
|
||||||
|
}
|
||||||
|
}
|
118
Source/cmGeneratorExpressionEvaluator.h
Normal file
118
Source/cmGeneratorExpressionEvaluator.h
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
/*============================================================================
|
||||||
|
CMake - Cross Platform Makefile Generator
|
||||||
|
Copyright 2012 Stephen Kelly <steveire@gmail.com>
|
||||||
|
|
||||||
|
Distributed under the OSI-approved BSD License (the "License");
|
||||||
|
see accompanying file Copyright.txt for details.
|
||||||
|
|
||||||
|
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||||
|
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the License for more information.
|
||||||
|
============================================================================*/
|
||||||
|
#ifndef cmGeneratorExpressionEvaluator_h
|
||||||
|
#define cmGeneratorExpressionEvaluator_h
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
struct cmGeneratorExpressionContext
|
||||||
|
{
|
||||||
|
cmListFileBacktrace Backtrace;
|
||||||
|
std::set<cmTarget*> Targets;
|
||||||
|
cmMakefile *Makefile;
|
||||||
|
const char *Config;
|
||||||
|
cmTarget *Target;
|
||||||
|
bool Quiet;
|
||||||
|
bool HadError;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
struct cmGeneratorExpressionEvaluator
|
||||||
|
{
|
||||||
|
cmGeneratorExpressionEvaluator() {}
|
||||||
|
virtual ~cmGeneratorExpressionEvaluator() {}
|
||||||
|
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
Text,
|
||||||
|
Generator
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual Type GetType() const = 0;
|
||||||
|
|
||||||
|
virtual std::string Evaluate(cmGeneratorExpressionContext *context
|
||||||
|
) const = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
cmGeneratorExpressionEvaluator(const cmGeneratorExpressionEvaluator &);
|
||||||
|
void operator=(const cmGeneratorExpressionEvaluator &);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TextContent : public cmGeneratorExpressionEvaluator
|
||||||
|
{
|
||||||
|
TextContent(const char *start, unsigned int length)
|
||||||
|
: Content(start), Length(length)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Evaluate(cmGeneratorExpressionContext *) const
|
||||||
|
{
|
||||||
|
return std::string(this->Content, this->Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Type GetType() const
|
||||||
|
{
|
||||||
|
return cmGeneratorExpressionEvaluator::Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Extend(unsigned int length)
|
||||||
|
{
|
||||||
|
this->Length += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int GetLength()
|
||||||
|
{
|
||||||
|
return this->Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char *Content;
|
||||||
|
unsigned int Length;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
struct GeneratorExpressionContent : public cmGeneratorExpressionEvaluator
|
||||||
|
{
|
||||||
|
GeneratorExpressionContent(const char *startContent, unsigned int length);
|
||||||
|
void SetIdentifier(std::vector<cmGeneratorExpressionEvaluator*> identifier)
|
||||||
|
{
|
||||||
|
this->IdentifierChildren = identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetParameters(
|
||||||
|
std::vector<std::vector<cmGeneratorExpressionEvaluator*> > parameters)
|
||||||
|
{
|
||||||
|
this->ParamChildren = parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type GetType() const
|
||||||
|
{
|
||||||
|
return cmGeneratorExpressionEvaluator::Generator;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Evaluate(cmGeneratorExpressionContext *context) const;
|
||||||
|
|
||||||
|
std::string GetOriginalExpression() const;
|
||||||
|
|
||||||
|
~GeneratorExpressionContent();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<cmGeneratorExpressionEvaluator*> IdentifierChildren;
|
||||||
|
std::vector<std::vector<cmGeneratorExpressionEvaluator*> > ParamChildren;
|
||||||
|
const char *StartContent;
|
||||||
|
unsigned int ContentLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
85
Source/cmGeneratorExpressionLexer.cxx
Normal file
85
Source/cmGeneratorExpressionLexer.cxx
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*============================================================================
|
||||||
|
CMake - Cross Platform Makefile Generator
|
||||||
|
Copyright 2012 Stephen Kelly <steveire@gmail.com>
|
||||||
|
|
||||||
|
Distributed under the OSI-approved BSD License (the "License");
|
||||||
|
see accompanying file Copyright.txt for details.
|
||||||
|
|
||||||
|
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||||
|
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the License for more information.
|
||||||
|
============================================================================*/
|
||||||
|
#include "cmGeneratorExpressionLexer.h"
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
cmGeneratorExpressionLexer::cmGeneratorExpressionLexer()
|
||||||
|
: SawBeginExpression(false), SawGeneratorExpression(false)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
static void InsertText(const char *upto, const char *c,
|
||||||
|
std::vector<cmGeneratorExpressionToken> &result)
|
||||||
|
{
|
||||||
|
if (upto != c)
|
||||||
|
{
|
||||||
|
result.push_back(cmGeneratorExpressionToken(
|
||||||
|
cmGeneratorExpressionToken::Text, upto, c - upto));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
std::vector<cmGeneratorExpressionToken>
|
||||||
|
cmGeneratorExpressionLexer::Tokenize(const char *input)
|
||||||
|
{
|
||||||
|
std::vector<cmGeneratorExpressionToken> result;
|
||||||
|
if (!input)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
const char *c = input;
|
||||||
|
const char *upto = c;
|
||||||
|
|
||||||
|
for ( ; *c; ++c)
|
||||||
|
{
|
||||||
|
if(c[0] == '$' && c[1] == '<')
|
||||||
|
{
|
||||||
|
InsertText(upto, c, result);
|
||||||
|
upto = c;
|
||||||
|
result.push_back(cmGeneratorExpressionToken(
|
||||||
|
cmGeneratorExpressionToken::BeginExpression, upto, 2));
|
||||||
|
upto = c + 2;
|
||||||
|
++c;
|
||||||
|
SawBeginExpression = true;
|
||||||
|
}
|
||||||
|
else if(c[0] == '>')
|
||||||
|
{
|
||||||
|
InsertText(upto, c, result);
|
||||||
|
upto = c;
|
||||||
|
result.push_back(cmGeneratorExpressionToken(
|
||||||
|
cmGeneratorExpressionToken::EndExpression, upto, 1));
|
||||||
|
upto = c + 1;
|
||||||
|
SawGeneratorExpression = SawBeginExpression;
|
||||||
|
}
|
||||||
|
else if(c[0] == ':')
|
||||||
|
{
|
||||||
|
InsertText(upto, c, result);
|
||||||
|
upto = c;
|
||||||
|
result.push_back(cmGeneratorExpressionToken(
|
||||||
|
cmGeneratorExpressionToken::ColonSeparator, upto, 1));
|
||||||
|
upto = c + 1;
|
||||||
|
}
|
||||||
|
else if(c[0] == ',')
|
||||||
|
{
|
||||||
|
InsertText(upto, c, result);
|
||||||
|
upto = c;
|
||||||
|
result.push_back(cmGeneratorExpressionToken(
|
||||||
|
cmGeneratorExpressionToken::CommaSeparator, upto, 1));
|
||||||
|
upto = c + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InsertText(upto, c, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
58
Source/cmGeneratorExpressionLexer.h
Normal file
58
Source/cmGeneratorExpressionLexer.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*============================================================================
|
||||||
|
CMake - Cross Platform Makefile Generator
|
||||||
|
Copyright 2012 Stephen Kelly <steveire@gmail.com>
|
||||||
|
|
||||||
|
Distributed under the OSI-approved BSD License (the "License");
|
||||||
|
see accompanying file Copyright.txt for details.
|
||||||
|
|
||||||
|
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||||
|
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the License for more information.
|
||||||
|
============================================================================*/
|
||||||
|
#ifndef cmGeneratorExpressionLexer_h
|
||||||
|
#define cmGeneratorExpressionLexer_h
|
||||||
|
|
||||||
|
#include "cmStandardIncludes.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
struct cmGeneratorExpressionToken
|
||||||
|
{
|
||||||
|
cmGeneratorExpressionToken(unsigned type, const char *c, unsigned l)
|
||||||
|
: TokenType(type), Content(c), Length(l)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
enum {
|
||||||
|
Text,
|
||||||
|
BeginExpression,
|
||||||
|
EndExpression,
|
||||||
|
ColonSeparator,
|
||||||
|
CommaSeparator
|
||||||
|
};
|
||||||
|
unsigned TokenType;
|
||||||
|
const char *Content;
|
||||||
|
unsigned Length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \class cmGeneratorExpressionLexer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class cmGeneratorExpressionLexer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cmGeneratorExpressionLexer();
|
||||||
|
|
||||||
|
std::vector<cmGeneratorExpressionToken> Tokenize(const char *input);
|
||||||
|
|
||||||
|
bool GetSawGeneratorExpression() const
|
||||||
|
{
|
||||||
|
return this->SawGeneratorExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool SawBeginExpression;
|
||||||
|
bool SawGeneratorExpression;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
235
Source/cmGeneratorExpressionParser.cxx
Normal file
235
Source/cmGeneratorExpressionParser.cxx
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
/*============================================================================
|
||||||
|
CMake - Cross Platform Makefile Generator
|
||||||
|
Copyright 2012 Stephen Kelly <steveire@gmail.com>
|
||||||
|
|
||||||
|
Distributed under the OSI-approved BSD License (the "License");
|
||||||
|
see accompanying file Copyright.txt for details.
|
||||||
|
|
||||||
|
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||||
|
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the License for more information.
|
||||||
|
============================================================================*/
|
||||||
|
|
||||||
|
#include "cmGeneratorExpressionParser.h"
|
||||||
|
|
||||||
|
#include "cmGeneratorExpressionEvaluator.h"
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
cmGeneratorExpressionParser::cmGeneratorExpressionParser(
|
||||||
|
const std::vector<cmGeneratorExpressionToken> &tokens)
|
||||||
|
: Tokens(tokens), NestingLevel(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmGeneratorExpressionParser::Parse(
|
||||||
|
std::vector<cmGeneratorExpressionEvaluator*> &result)
|
||||||
|
{
|
||||||
|
it = this->Tokens.begin();
|
||||||
|
|
||||||
|
while (this->it != this->Tokens.end())
|
||||||
|
{
|
||||||
|
this->ParseContent(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
static void extendText(std::vector<cmGeneratorExpressionEvaluator*> &result,
|
||||||
|
std::vector<cmGeneratorExpressionToken>::const_iterator it)
|
||||||
|
{
|
||||||
|
if (result.size() > 0
|
||||||
|
&& (*(result.end() - 1))->GetType()
|
||||||
|
== cmGeneratorExpressionEvaluator::Text)
|
||||||
|
{
|
||||||
|
TextContent *textContent = static_cast<TextContent*>(*(result.end() - 1));
|
||||||
|
textContent->Extend(it->Length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TextContent *textContent = new TextContent(it->Content, it->Length);
|
||||||
|
result.push_back(textContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
static void extendResult(std::vector<cmGeneratorExpressionEvaluator*> &result,
|
||||||
|
const std::vector<cmGeneratorExpressionEvaluator*> &contents)
|
||||||
|
{
|
||||||
|
if (result.size() > 0
|
||||||
|
&& (*(result.end() - 1))->GetType()
|
||||||
|
== cmGeneratorExpressionEvaluator::Text
|
||||||
|
&& (*contents.begin())->GetType()
|
||||||
|
== cmGeneratorExpressionEvaluator::Text)
|
||||||
|
{
|
||||||
|
TextContent *textContent = static_cast<TextContent*>(*(result.end() - 1));
|
||||||
|
textContent->Extend(
|
||||||
|
static_cast<TextContent*>(*contents.begin())->GetLength());
|
||||||
|
delete *contents.begin();
|
||||||
|
result.insert(result.end(), contents.begin() + 1, contents.end());
|
||||||
|
} else {
|
||||||
|
result.insert(result.end(), contents.begin(), contents.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmGeneratorExpressionParser::ParseGeneratorExpression(
|
||||||
|
std::vector<cmGeneratorExpressionEvaluator*> &result)
|
||||||
|
{
|
||||||
|
unsigned int nestedLevel = this->NestingLevel;
|
||||||
|
++this->NestingLevel;
|
||||||
|
|
||||||
|
std::vector<cmGeneratorExpressionToken>::const_iterator startToken
|
||||||
|
= this->it - 1;
|
||||||
|
|
||||||
|
std::vector<cmGeneratorExpressionEvaluator*> identifier;
|
||||||
|
while(this->it->TokenType != cmGeneratorExpressionToken::EndExpression
|
||||||
|
&& this->it->TokenType != cmGeneratorExpressionToken::ColonSeparator)
|
||||||
|
{
|
||||||
|
this->ParseContent(identifier);
|
||||||
|
if (this->it == this->Tokens.end())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (identifier.empty())
|
||||||
|
{
|
||||||
|
// ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->it->TokenType == cmGeneratorExpressionToken::EndExpression)
|
||||||
|
{
|
||||||
|
GeneratorExpressionContent *content = new GeneratorExpressionContent(
|
||||||
|
startToken->Content, this->it->Content
|
||||||
|
- startToken->Content
|
||||||
|
+ this->it->Length);
|
||||||
|
++this->it;
|
||||||
|
--this->NestingLevel;
|
||||||
|
content->SetIdentifier(identifier);
|
||||||
|
result.push_back(content);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<cmGeneratorExpressionEvaluator*> > parameters;
|
||||||
|
std::vector<std::vector<cmGeneratorExpressionToken>::const_iterator>
|
||||||
|
commaTokens;
|
||||||
|
std::vector<cmGeneratorExpressionToken>::const_iterator colonToken;
|
||||||
|
if (this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
|
||||||
|
{
|
||||||
|
colonToken = this->it;
|
||||||
|
parameters.resize(parameters.size() + 1);
|
||||||
|
++this->it;
|
||||||
|
while(this->it->TokenType != cmGeneratorExpressionToken::EndExpression)
|
||||||
|
{
|
||||||
|
this->ParseContent(*(parameters.end() - 1));
|
||||||
|
if (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator)
|
||||||
|
{
|
||||||
|
commaTokens.push_back(this->it);
|
||||||
|
parameters.resize(parameters.size() + 1);
|
||||||
|
++this->it;
|
||||||
|
}
|
||||||
|
if (this->it == this->Tokens.end())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(this->it->TokenType == cmGeneratorExpressionToken::EndExpression)
|
||||||
|
{
|
||||||
|
--this->NestingLevel;
|
||||||
|
++this->it;
|
||||||
|
}
|
||||||
|
if (parameters.empty())
|
||||||
|
{
|
||||||
|
// ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nestedLevel != this->NestingLevel)
|
||||||
|
{
|
||||||
|
// There was a '$<' in the text, but no corresponding '>'. Rebuild to
|
||||||
|
// treat the '$<' as having been plain text, along with the
|
||||||
|
// corresponding : and , tokens that might have been found.
|
||||||
|
extendText(result, startToken);
|
||||||
|
extendResult(result, identifier);
|
||||||
|
if (!parameters.empty())
|
||||||
|
{
|
||||||
|
extendText(result, colonToken);
|
||||||
|
|
||||||
|
typedef std::vector<cmGeneratorExpressionEvaluator*> EvaluatorVector;
|
||||||
|
typedef std::vector<cmGeneratorExpressionToken> TokenVector;
|
||||||
|
std::vector<EvaluatorVector>::const_iterator pit = parameters.begin();
|
||||||
|
const std::vector<EvaluatorVector>::const_iterator pend =
|
||||||
|
parameters.end();
|
||||||
|
std::vector<TokenVector::const_iterator>::const_iterator commaIt =
|
||||||
|
commaTokens.begin();
|
||||||
|
for ( ; pit != pend; ++pit, ++commaIt)
|
||||||
|
{
|
||||||
|
extendResult(result, *pit);
|
||||||
|
if (commaIt != commaTokens.end())
|
||||||
|
{
|
||||||
|
extendText(result, *commaIt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int contentLength = ((this->it - 1)->Content
|
||||||
|
- startToken->Content)
|
||||||
|
+ (this->it - 1)->Length;
|
||||||
|
GeneratorExpressionContent *content = new GeneratorExpressionContent(
|
||||||
|
startToken->Content, contentLength);
|
||||||
|
content->SetIdentifier(identifier);
|
||||||
|
content->SetParameters(parameters);
|
||||||
|
result.push_back(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmGeneratorExpressionParser::ParseContent(
|
||||||
|
std::vector<cmGeneratorExpressionEvaluator*> &result)
|
||||||
|
{
|
||||||
|
switch(this->it->TokenType)
|
||||||
|
{
|
||||||
|
case cmGeneratorExpressionToken::Text:
|
||||||
|
{
|
||||||
|
if (this->NestingLevel == 0)
|
||||||
|
{
|
||||||
|
if (result.size() > 0
|
||||||
|
&& (*(result.end() - 1))->GetType()
|
||||||
|
== cmGeneratorExpressionEvaluator::Text)
|
||||||
|
{
|
||||||
|
// A comma in 'plain text' could have split text that should
|
||||||
|
// otherwise be continuous. Extend the last text content instead of
|
||||||
|
// creating a new one.
|
||||||
|
TextContent *textContent =
|
||||||
|
static_cast<TextContent*>(*(result.end() - 1));
|
||||||
|
textContent->Extend(this->it->Length);
|
||||||
|
++this->it;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmGeneratorExpressionEvaluator* n = new TextContent(this->it->Content,
|
||||||
|
this->it->Length);
|
||||||
|
result.push_back(n);
|
||||||
|
++this->it;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
case cmGeneratorExpressionToken::BeginExpression:
|
||||||
|
++this->it;
|
||||||
|
this->ParseGeneratorExpression(result);
|
||||||
|
return;
|
||||||
|
case cmGeneratorExpressionToken::EndExpression:
|
||||||
|
case cmGeneratorExpressionToken::ColonSeparator:
|
||||||
|
case cmGeneratorExpressionToken::CommaSeparator:
|
||||||
|
if (this->NestingLevel == 0)
|
||||||
|
{
|
||||||
|
extendText(result, this->it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: Unreachable. Assert?
|
||||||
|
}
|
||||||
|
++this->it;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Unreachable. Assert?
|
||||||
|
}
|
45
Source/cmGeneratorExpressionParser.h
Normal file
45
Source/cmGeneratorExpressionParser.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*============================================================================
|
||||||
|
CMake - Cross Platform Makefile Generator
|
||||||
|
Copyright 2012 Stephen Kelly <steveire@gmail.com>
|
||||||
|
|
||||||
|
Distributed under the OSI-approved BSD License (the "License");
|
||||||
|
see accompanying file Copyright.txt for details.
|
||||||
|
|
||||||
|
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||||
|
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the License for more information.
|
||||||
|
============================================================================*/
|
||||||
|
#ifndef cmGeneratorExpressionParser_h
|
||||||
|
#define cmGeneratorExpressionParser_h
|
||||||
|
|
||||||
|
#include "cmGeneratorExpressionLexer.h"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "cmListFileCache.h"
|
||||||
|
|
||||||
|
class cmMakefile;
|
||||||
|
class cmTarget;
|
||||||
|
struct cmGeneratorExpressionEvaluator;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
struct cmGeneratorExpressionParser
|
||||||
|
{
|
||||||
|
cmGeneratorExpressionParser(
|
||||||
|
const std::vector<cmGeneratorExpressionToken> &tokens);
|
||||||
|
|
||||||
|
void Parse(std::vector<cmGeneratorExpressionEvaluator*> &result);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ParseContent(std::vector<cmGeneratorExpressionEvaluator*> &);
|
||||||
|
void ParseGeneratorExpression(
|
||||||
|
std::vector<cmGeneratorExpressionEvaluator*> &);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<cmGeneratorExpressionToken>::const_iterator it;
|
||||||
|
const std::vector<cmGeneratorExpressionToken> Tokens;
|
||||||
|
unsigned int NestingLevel;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -1623,7 +1623,11 @@ cmTargetTraceDependencies
|
|||||||
{
|
{
|
||||||
// Transform command names that reference targets built in this
|
// Transform command names that reference targets built in this
|
||||||
// project to corresponding target-level dependencies.
|
// project to corresponding target-level dependencies.
|
||||||
cmGeneratorExpression ge(this->Makefile, 0, cc.GetBacktrace(), true);
|
cmGeneratorExpression ge(cc.GetBacktrace());
|
||||||
|
|
||||||
|
// Add target-level dependencies referenced by generator expressions.
|
||||||
|
std::set<cmTarget*> targets;
|
||||||
|
|
||||||
for(cmCustomCommandLines::const_iterator cit = cc.GetCommandLines().begin();
|
for(cmCustomCommandLines::const_iterator cit = cc.GetCommandLines().begin();
|
||||||
cit != cc.GetCommandLines().end(); ++cit)
|
cit != cc.GetCommandLines().end(); ++cit)
|
||||||
{
|
{
|
||||||
@ -1645,12 +1649,17 @@ cmTargetTraceDependencies
|
|||||||
for(cmCustomCommandLine::const_iterator cli = cit->begin();
|
for(cmCustomCommandLine::const_iterator cli = cit->begin();
|
||||||
cli != cit->end(); ++cli)
|
cli != cit->end(); ++cli)
|
||||||
{
|
{
|
||||||
ge.Process(*cli);
|
const cmCompiledGeneratorExpression &cge = ge.Parse(*cli);
|
||||||
|
cge.Evaluate(this->Makefile, 0, true);
|
||||||
|
std::set<cmTarget*> geTargets = cge.GetTargets();
|
||||||
|
for(std::set<cmTarget*>::const_iterator it = geTargets.begin();
|
||||||
|
it != geTargets.end(); ++it)
|
||||||
|
{
|
||||||
|
targets.insert(*it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add target-level dependencies referenced by generator expressions.
|
|
||||||
std::set<cmTarget*> targets = ge.GetTargets();
|
|
||||||
for(std::set<cmTarget*>::iterator ti = targets.begin();
|
for(std::set<cmTarget*>::iterator ti = targets.begin();
|
||||||
ti != targets.end(); ++ti)
|
ti != targets.end(); ++ti)
|
||||||
{
|
{
|
||||||
|
@ -91,8 +91,7 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
|
|||||||
this->TestGenerated = true;
|
this->TestGenerated = true;
|
||||||
|
|
||||||
// Set up generator expression evaluation context.
|
// Set up generator expression evaluation context.
|
||||||
cmMakefile* mf = this->Test->GetMakefile();
|
cmGeneratorExpression ge(this->Test->GetBacktrace());
|
||||||
cmGeneratorExpression ge(mf, config, this->Test->GetBacktrace());
|
|
||||||
|
|
||||||
// Start the test command.
|
// Start the test command.
|
||||||
os << indent << "ADD_TEST(" << this->Test->GetName() << " ";
|
os << indent << "ADD_TEST(" << this->Test->GetName() << " ";
|
||||||
@ -103,6 +102,7 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
|
|||||||
// Check whether the command executable is a target whose name is to
|
// Check whether the command executable is a target whose name is to
|
||||||
// be translated.
|
// be translated.
|
||||||
std::string exe = command[0];
|
std::string exe = command[0];
|
||||||
|
cmMakefile* mf = this->Test->GetMakefile();
|
||||||
cmTarget* target = mf->FindTargetToUse(exe.c_str());
|
cmTarget* target = mf->FindTargetToUse(exe.c_str());
|
||||||
if(target && target->GetType() == cmTarget::EXECUTABLE)
|
if(target && target->GetType() == cmTarget::EXECUTABLE)
|
||||||
{
|
{
|
||||||
@ -112,7 +112,7 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Use the command name given.
|
// Use the command name given.
|
||||||
exe = ge.Process(exe.c_str());
|
exe = ge.Parse(exe.c_str()).Evaluate(mf, config);
|
||||||
cmSystemTools::ConvertToUnixSlashes(exe);
|
cmSystemTools::ConvertToUnixSlashes(exe);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
|
|||||||
for(std::vector<std::string>::const_iterator ci = command.begin()+1;
|
for(std::vector<std::string>::const_iterator ci = command.begin()+1;
|
||||||
ci != command.end(); ++ci)
|
ci != command.end(); ++ci)
|
||||||
{
|
{
|
||||||
os << " " << lg->EscapeForCMake(ge.Process(*ci));
|
os << " " << lg->EscapeForCMake(ge.Parse(*ci).Evaluate(mf, config));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finish the test command.
|
// Finish the test command.
|
||||||
|
@ -1,9 +1,18 @@
|
|||||||
|
CMake Error at BadAND.cmake:1 \(add_custom_target\):
|
||||||
|
Error evaluating generator expression:
|
||||||
|
|
||||||
|
\$<AND>
|
||||||
|
|
||||||
|
\$<AND> expression requires at least one parameter.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
||||||
|
+
|
||||||
CMake Error at BadAND.cmake:1 \(add_custom_target\):
|
CMake Error at BadAND.cmake:1 \(add_custom_target\):
|
||||||
Error evaluating generator expression:
|
Error evaluating generator expression:
|
||||||
|
|
||||||
\$<AND:>
|
\$<AND:>
|
||||||
|
|
||||||
AND requires one or more comma-separated '0' or '1' values.
|
Parameters to \$<AND> must resolve to either '0' or '1'.
|
||||||
Call Stack \(most recent call first\):
|
Call Stack \(most recent call first\):
|
||||||
CMakeLists.txt:3 \(include\)
|
CMakeLists.txt:3 \(include\)
|
||||||
+
|
+
|
||||||
@ -12,6 +21,24 @@ CMake Error at BadAND.cmake:1 \(add_custom_target\):
|
|||||||
|
|
||||||
\$<AND:,>
|
\$<AND:,>
|
||||||
|
|
||||||
AND requires one or more comma-separated '0' or '1' values.
|
Parameters to \$<AND> must resolve to either '0' or '1'.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
||||||
|
+
|
||||||
|
CMake Error at BadAND.cmake:1 \(add_custom_target\):
|
||||||
|
Error evaluating generator expression:
|
||||||
|
|
||||||
|
\$<AND:01>
|
||||||
|
|
||||||
|
Parameters to \$<AND> must resolve to either '0' or '1'.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
||||||
|
+
|
||||||
|
CMake Error at BadAND.cmake:1 \(add_custom_target\):
|
||||||
|
Error evaluating generator expression:
|
||||||
|
|
||||||
|
\$<AND:nothing>
|
||||||
|
|
||||||
|
Parameters to \$<AND> must resolve to either '0' or '1'.
|
||||||
Call Stack \(most recent call first\):
|
Call Stack \(most recent call first\):
|
||||||
CMakeLists.txt:3 \(include\)$
|
CMakeLists.txt:3 \(include\)$
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
add_custom_target(check ALL COMMAND check
|
add_custom_target(check ALL COMMAND check
|
||||||
|
$<AND>
|
||||||
$<AND:>
|
$<AND:>
|
||||||
$<AND:,>
|
$<AND:,>
|
||||||
|
$<AND:01>
|
||||||
|
$<AND:nothing>
|
||||||
VERBATIM)
|
VERBATIM)
|
||||||
|
@ -1,8 +1,44 @@
|
|||||||
|
CMake Error at BadCONFIG.cmake:1 \(add_custom_target\):
|
||||||
|
Error evaluating generator expression:
|
||||||
|
|
||||||
|
\$<CONFIG>
|
||||||
|
|
||||||
|
\$<CONFIG> expression requires exactly one parameter.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
||||||
|
+
|
||||||
CMake Error at BadCONFIG.cmake:1 \(add_custom_target\):
|
CMake Error at BadCONFIG.cmake:1 \(add_custom_target\):
|
||||||
Error evaluating generator expression:
|
Error evaluating generator expression:
|
||||||
|
|
||||||
\$<CONFIG:.>
|
\$<CONFIG:.>
|
||||||
|
|
||||||
|
Expression syntax not recognized.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
||||||
|
+
|
||||||
|
CMake Error at BadCONFIG.cmake:1 \(add_custom_target\):
|
||||||
|
Error evaluating generator expression:
|
||||||
|
|
||||||
|
\$<CONFIG:Foo,Bar>
|
||||||
|
|
||||||
|
\$<CONFIG> expression requires exactly one parameter.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
||||||
|
+
|
||||||
|
CMake Error at BadCONFIG.cmake:1 \(add_custom_target\):
|
||||||
|
Error evaluating generator expression:
|
||||||
|
|
||||||
|
\$<CONFIG:Foo-Bar>
|
||||||
|
|
||||||
|
Expression syntax not recognized.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
||||||
|
+
|
||||||
|
CMake Error at BadCONFIG.cmake:1 \(add_custom_target\):
|
||||||
|
Error evaluating generator expression:
|
||||||
|
|
||||||
|
\$<CONFIG:Foo-Nested>
|
||||||
|
|
||||||
Expression syntax not recognized.
|
Expression syntax not recognized.
|
||||||
Call Stack \(most recent call first\):
|
Call Stack \(most recent call first\):
|
||||||
CMakeLists.txt:3 \(include\)$
|
CMakeLists.txt:3 \(include\)$
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
add_custom_target(check ALL COMMAND check
|
add_custom_target(check ALL COMMAND check
|
||||||
|
$<CONFIG>
|
||||||
$<CONFIG:.>
|
$<CONFIG:.>
|
||||||
|
$<CONFIG:Foo,Bar>
|
||||||
|
$<CONFIG:Foo-Bar>
|
||||||
|
$<$<CONFIG:Foo-Nested>:foo>
|
||||||
VERBATIM)
|
VERBATIM)
|
||||||
|
@ -1,9 +1,17 @@
|
|||||||
CMake Error at BadNOT.cmake:1 \(add_custom_target\):
|
CMake Error at BadNOT.cmake:1 \(add_custom_target\):
|
||||||
|
Error evaluating generator expression:
|
||||||
|
|
||||||
|
\$<NOT>
|
||||||
|
|
||||||
|
\$<NOT> expression requires exactly one parameter.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
||||||
|
+CMake Error at BadNOT.cmake:1 \(add_custom_target\):
|
||||||
Error evaluating generator expression:
|
Error evaluating generator expression:
|
||||||
|
|
||||||
\$<NOT:>
|
\$<NOT:>
|
||||||
|
|
||||||
NOT requires exactly one '0' or '1' value.
|
\$<NOT> parameter must resolve to exactly one '0' or '1' value.
|
||||||
Call Stack \(most recent call first\):
|
Call Stack \(most recent call first\):
|
||||||
CMakeLists.txt:3 \(include\)
|
CMakeLists.txt:3 \(include\)
|
||||||
+
|
+
|
||||||
@ -12,7 +20,7 @@ CMake Error at BadNOT.cmake:1 \(add_custom_target\):
|
|||||||
|
|
||||||
\$<NOT:,>
|
\$<NOT:,>
|
||||||
|
|
||||||
NOT requires exactly one '0' or '1' value.
|
\$<NOT> parameter must resolve to exactly one '0' or '1' value.
|
||||||
Call Stack \(most recent call first\):
|
Call Stack \(most recent call first\):
|
||||||
CMakeLists.txt:3 \(include\)
|
CMakeLists.txt:3 \(include\)
|
||||||
+
|
+
|
||||||
@ -21,6 +29,24 @@ CMake Error at BadNOT.cmake:1 \(add_custom_target\):
|
|||||||
|
|
||||||
\$<NOT:0,1>
|
\$<NOT:0,1>
|
||||||
|
|
||||||
NOT requires exactly one '0' or '1' value.
|
\$<NOT> expression requires exactly one parameter.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
||||||
|
+
|
||||||
|
CMake Error at BadNOT.cmake:1 \(add_custom_target\):
|
||||||
|
Error evaluating generator expression:
|
||||||
|
|
||||||
|
\$<NOT:01>
|
||||||
|
|
||||||
|
\$<NOT> parameter must resolve to exactly one '0' or '1' value.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
||||||
|
+
|
||||||
|
CMake Error at BadNOT.cmake:1 \(add_custom_target\):
|
||||||
|
Error evaluating generator expression:
|
||||||
|
|
||||||
|
\$<NOT:nothing>
|
||||||
|
|
||||||
|
\$<NOT> parameter must resolve to exactly one '0' or '1' value.
|
||||||
Call Stack \(most recent call first\):
|
Call Stack \(most recent call first\):
|
||||||
CMakeLists.txt:3 \(include\)$
|
CMakeLists.txt:3 \(include\)$
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
add_custom_target(check ALL COMMAND check
|
add_custom_target(check ALL COMMAND check
|
||||||
|
$<NOT>
|
||||||
$<NOT:>
|
$<NOT:>
|
||||||
$<NOT:,>
|
$<NOT:,>
|
||||||
$<NOT:0,1>
|
$<NOT:0,1>
|
||||||
|
$<NOT:01>
|
||||||
|
$<NOT:nothing>
|
||||||
VERBATIM)
|
VERBATIM)
|
||||||
|
@ -1,9 +1,18 @@
|
|||||||
|
CMake Error at BadOR.cmake:1 \(add_custom_target\):
|
||||||
|
Error evaluating generator expression:
|
||||||
|
|
||||||
|
\$<OR>
|
||||||
|
|
||||||
|
\$<OR> expression requires at least one parameter.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
||||||
|
+
|
||||||
CMake Error at BadOR.cmake:1 \(add_custom_target\):
|
CMake Error at BadOR.cmake:1 \(add_custom_target\):
|
||||||
Error evaluating generator expression:
|
Error evaluating generator expression:
|
||||||
|
|
||||||
\$<OR:>
|
\$<OR:>
|
||||||
|
|
||||||
OR requires one or more comma-separated '0' or '1' values.
|
Parameters to \$<OR> must resolve to either '0' or '1'.
|
||||||
Call Stack \(most recent call first\):
|
Call Stack \(most recent call first\):
|
||||||
CMakeLists.txt:3 \(include\)
|
CMakeLists.txt:3 \(include\)
|
||||||
+
|
+
|
||||||
@ -12,6 +21,24 @@ CMake Error at BadOR.cmake:1 \(add_custom_target\):
|
|||||||
|
|
||||||
\$<OR:,>
|
\$<OR:,>
|
||||||
|
|
||||||
OR requires one or more comma-separated '0' or '1' values.
|
Parameters to \$<OR> must resolve to either '0' or '1'.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
||||||
|
+
|
||||||
|
CMake Error at BadOR.cmake:1 \(add_custom_target\):
|
||||||
|
Error evaluating generator expression:
|
||||||
|
|
||||||
|
\$<OR:01>
|
||||||
|
|
||||||
|
Parameters to \$<OR> must resolve to either '0' or '1'.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
||||||
|
+
|
||||||
|
CMake Error at BadOR.cmake:1 \(add_custom_target\):
|
||||||
|
Error evaluating generator expression:
|
||||||
|
|
||||||
|
\$<OR:nothing>
|
||||||
|
|
||||||
|
Parameters to \$<OR> must resolve to either '0' or '1'.
|
||||||
Call Stack \(most recent call first\):
|
Call Stack \(most recent call first\):
|
||||||
CMakeLists.txt:3 \(include\)$
|
CMakeLists.txt:3 \(include\)$
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
add_custom_target(check ALL COMMAND check
|
add_custom_target(check ALL COMMAND check
|
||||||
|
$<OR>
|
||||||
$<OR:>
|
$<OR:>
|
||||||
$<OR:,>
|
$<OR:,>
|
||||||
|
$<OR:01>
|
||||||
|
$<OR:nothing>
|
||||||
VERBATIM)
|
VERBATIM)
|
||||||
|
@ -202,6 +202,9 @@ CMAKE_CXX_SOURCES="\
|
|||||||
cmInstallDirectoryGenerator \
|
cmInstallDirectoryGenerator \
|
||||||
cmGeneratedFileStream \
|
cmGeneratedFileStream \
|
||||||
cmGeneratorTarget \
|
cmGeneratorTarget \
|
||||||
|
cmGeneratorExpressionEvaluator \
|
||||||
|
cmGeneratorExpressionLexer \
|
||||||
|
cmGeneratorExpressionParser \
|
||||||
cmGeneratorExpression \
|
cmGeneratorExpression \
|
||||||
cmGlobalGenerator \
|
cmGlobalGenerator \
|
||||||
cmLocalGenerator \
|
cmLocalGenerator \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user