Merge topic 'generator-expression-target-properties'

083de7e Process generator expressions in the COMPILE_DEFINITIONS target property.
08cb4fa Process generator expressions in the INCLUDE_DIRECTORIES property.
0ef091d Early return if there is no target.
eb250cd Add a self-reference check for target properties.
7e80747 Add API to check that dependent target properties form a DAG.
239ac84 Add a generator expression for target properties.
e028381 Extend the generator expression language with more logic.
b8e61d6 Refactor GetCompileDefinitions a bit.
2c2b25b Return a std::string from GetCompileDefinitions.
b7e48e0 Add an AppendDefines std::string overload.
9a16087 Convert paths in INCLUDE_DIRECTORIES property to Unix slashes.
4557c8d Don't prepend a path before generator expressions in include_directories.
c6abc41 Add include guard for cmGeneratorExpression.
0ff4e3f Port remaining code to GetCompileDefinitions().
f178d53 Fix indentation in the code blocks generator.
This commit is contained in:
Brad King 2012-09-28 17:15:03 -04:00 committed by CMake Topic Stage
commit 103d99338a
47 changed files with 667 additions and 122 deletions

View File

@ -183,6 +183,8 @@ set(SRCS
cmFileTimeComparison.cxx
cmFileTimeComparison.h
cmGeneratedFileStream.cxx
cmGeneratorExpressionDAGChecker.cxx
cmGeneratorExpressionDAGChecker.h
cmGeneratorExpressionEvaluator.cxx
cmGeneratorExpressionEvaluator.h
cmGeneratorExpressionLexer.cxx

View File

@ -81,7 +81,7 @@ public:
"\n"
"Arguments after COMMAND may use \"generator expressions\" with the "
"syntax \"$<...>\". "
CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
CM_DOCUMENT_ADD_TEST_GENERATOR_EXPRESSIONS
"Example usage:\n"
" add_test(NAME mytest\n"
" COMMAND testDriver --config $<CONFIGURATION>\n"

View File

@ -12,7 +12,7 @@
#ifndef cmDocumentGeneratorExpressions_h
#define cmDocumentGeneratorExpressions_h
#define CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS \
#define CM_DOCUMENT_ADD_TEST_GENERATOR_EXPRESSIONS \
"Generator expressions are evaluted during build system generation " \
"to produce information specific to each build configuration. " \
"Valid expressions are:\n" \
@ -20,6 +20,12 @@
" $<1:...> = content of \"...\"\n" \
" $<CONFIG:cfg> = '1' if config is \"cfg\", else '0'\n" \
" $<CONFIGURATION> = configuration name\n" \
" $<BOOL:...> = '1' if the '...' is true, else '0'\n" \
" $<STREQUAL:a,b> = '1' if a is STREQUAL b, else '0'\n" \
" $<ANGLE-R> = A literal '>'. Used to compare " \
"strings which contain a '>' for example.\n" \
" $<COMMA> = A literal ','. Used to compare " \
"strings which contain a ',' for example.\n" \
" $<TARGET_FILE:tgt> = main file (.exe, .so.1.2, .a)\n" \
" $<TARGET_LINKER_FILE:tgt> = file used to link (.a, .lib, .so)\n" \
" $<TARGET_SONAME_FILE:tgt> = file with soname (.so.3)\n" \
@ -29,11 +35,20 @@
" $<TARGET_FILE_DIR:tgt>/$<TARGET_FILE_NAME:tgt>\n" \
" $<TARGET_LINKER_FILE_DIR:tgt>/$<TARGET_LINKER_FILE_NAME:tgt>\n" \
" $<TARGET_SONAME_FILE_DIR:tgt>/$<TARGET_SONAME_FILE_NAME:tgt>\n" \
" $<TARGET_PROPERTY:tgt,prop> = The value of the property prop\n" \
"the target tgt. Note that tgt is not added as a dependency of the " \
"target this expression is evaluated on.\n" \
"Boolean expressions:\n" \
" $<AND:?[,?]...> = '1' if all '?' are '1', else '0'\n" \
" $<OR:?[,?]...> = '0' if all '?' are '0', else '1'\n" \
" $<NOT:?> = '0' if '?' is '1', else '1'\n" \
"where '?' is always either '0' or '1'.\n" \
#define CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS \
CM_DOCUMENT_ADD_TEST_GENERATOR_EXPRESSIONS \
"Expressions with an implicit 'this' target:" \
" $<TARGET_PROPERTY:prop> = The value of the property prop on\n" \
"the target on which the generator expression is evaluated.\n" \
""
#endif

View File

@ -617,14 +617,17 @@ void cmExtraCodeBlocksGenerator::AppendTarget(cmGeneratedFileStream& fout,
" <Option compiler=\"" << compiler << "\" />\n"
" <Compiler>\n";
cmGeneratorTarget *gtgt = this->GlobalGenerator
->GetGeneratorTarget(target);
// the compilerdefines for this target
const char* cdefs = target->GetMakefile()->GetProperty(
"COMPILE_DEFINITIONS");
if(cdefs)
std::string cdefs = gtgt->GetCompileDefinitions();
if(cdefs.empty())
{
// Expand the list.
std::vector<std::string> defs;
cmSystemTools::ExpandListArgument(cdefs, defs);
cmSystemTools::ExpandListArgument(cdefs.c_str(), defs);
for(std::vector<std::string>::const_iterator di = defs.begin();
di != defs.end(); ++di)
{
@ -633,59 +636,57 @@ void cmExtraCodeBlocksGenerator::AppendTarget(cmGeneratedFileStream& fout,
}
}
// the include directories for this target
std::set<std::string> uniqIncludeDirs;
// the include directories for this target
std::set<std::string> uniqIncludeDirs;
cmGeneratorTarget *gtgt = this->GlobalGenerator
->GetGeneratorTarget(target);
std::vector<std::string> includes;
target->GetMakefile()->GetLocalGenerator()->
GetIncludeDirectories(includes, gtgt);
for(std::vector<std::string>::const_iterator dirIt=includes.begin();
dirIt != includes.end();
std::vector<std::string> includes;
target->GetMakefile()->GetLocalGenerator()->
GetIncludeDirectories(includes, gtgt);
for(std::vector<std::string>::const_iterator dirIt=includes.begin();
dirIt != includes.end();
++dirIt)
{
uniqIncludeDirs.insert(*dirIt);
}
std::string systemIncludeDirs = makefile->GetSafeDefinition(
"CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS");
if (!systemIncludeDirs.empty())
{
std::vector<std::string> dirs;
cmSystemTools::ExpandListArgument(systemIncludeDirs.c_str(), dirs);
for(std::vector<std::string>::const_iterator dirIt=dirs.begin();
dirIt != dirs.end();
++dirIt)
{
uniqIncludeDirs.insert(*dirIt);
}
}
std::string systemIncludeDirs = makefile->GetSafeDefinition(
"CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS");
if (!systemIncludeDirs.empty())
{
std::vector<std::string> dirs;
cmSystemTools::ExpandListArgument(systemIncludeDirs.c_str(), dirs);
for(std::vector<std::string>::const_iterator dirIt=dirs.begin();
dirIt != dirs.end();
++dirIt)
{
uniqIncludeDirs.insert(*dirIt);
}
}
systemIncludeDirs = makefile->GetSafeDefinition(
"CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS");
if (!systemIncludeDirs.empty())
{
std::vector<std::string> dirs;
cmSystemTools::ExpandListArgument(systemIncludeDirs.c_str(), dirs);
for(std::vector<std::string>::const_iterator dirIt=dirs.begin();
dirIt != dirs.end();
++dirIt)
{
uniqIncludeDirs.insert(*dirIt);
}
}
for(std::set<std::string>::const_iterator dirIt=uniqIncludeDirs.begin();
dirIt != uniqIncludeDirs.end();
systemIncludeDirs = makefile->GetSafeDefinition(
"CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS");
if (!systemIncludeDirs.empty())
{
std::vector<std::string> dirs;
cmSystemTools::ExpandListArgument(systemIncludeDirs.c_str(), dirs);
for(std::vector<std::string>::const_iterator dirIt=dirs.begin();
dirIt != dirs.end();
++dirIt)
{
fout <<" <Add directory=\"" << dirIt->c_str() << "\" />\n";
uniqIncludeDirs.insert(*dirIt);
}
fout<<" </Compiler>\n";
}
else // e.g. all and the GLOBAL and UTILITY targets
for(std::set<std::string>::const_iterator dirIt=uniqIncludeDirs.begin();
dirIt != uniqIncludeDirs.end();
++dirIt)
{
fout <<" <Add directory=\"" << dirIt->c_str() << "\" />\n";
}
fout<<" </Compiler>\n";
}
else // e.g. all and the GLOBAL and UTILITY targets
{
fout<<" <Option working_dir=\""
<< makefile->GetStartOutputDirectory() << "\" />\n"

View File

@ -19,6 +19,7 @@
#include "cmGeneratorExpressionEvaluator.h"
#include "cmGeneratorExpressionLexer.h"
#include "cmGeneratorExpressionParser.h"
#include "cmGeneratorExpressionDAGChecker.h"
//----------------------------------------------------------------------------
cmGeneratorExpression::cmGeneratorExpression(
@ -65,7 +66,9 @@ cmGeneratorExpression::~cmGeneratorExpression()
//----------------------------------------------------------------------------
const char *cmCompiledGeneratorExpression::Evaluate(
cmMakefile* mf, const char* config, bool quiet) const
cmMakefile* mf, const char* config, bool quiet,
cmGeneratorTarget *target,
cmGeneratorExpressionDAGChecker *dagChecker) const
{
if (!this->NeedsParsing)
{
@ -84,11 +87,12 @@ const char *cmCompiledGeneratorExpression::Evaluate(
context.Config = config;
context.Quiet = quiet;
context.HadError = false;
context.Target = target;
context.Backtrace = this->Backtrace;
for ( ; it != end; ++it)
{
this->Output += (*it)->Evaluate(&context);
this->Output += (*it)->Evaluate(&context, dagChecker);
if (context.HadError)
{
this->Output = "";

View File

@ -9,6 +9,10 @@
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the License for more information.
============================================================================*/
#ifndef cmGeneratorExpression_h
#define cmGeneratorExpression_h
#include "cmStandardIncludes.h"
#include <stack>
@ -16,10 +20,12 @@
#include <cmsys/RegularExpression.hxx>
class cmTarget;
class cmGeneratorTarget;
class cmMakefile;
class cmListFileBacktrace;
struct cmGeneratorExpressionEvaluator;
struct cmGeneratorExpressionDAGChecker;
class cmCompiledGeneratorExpression;
@ -54,7 +60,9 @@ class cmCompiledGeneratorExpression
{
public:
const char* Evaluate(cmMakefile* mf, const char* config,
bool quiet = false) const;
bool quiet = false,
cmGeneratorTarget *target = 0,
cmGeneratorExpressionDAGChecker *dagChecker = 0) const;
/** Get set of targets found during evaluations. */
std::set<cmTarget*> const& GetTargets() const
@ -80,3 +88,5 @@ private:
mutable std::set<cmTarget*> Targets;
mutable std::string Output;
};
#endif

View File

@ -0,0 +1,106 @@
/*============================================================================
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 "cmGeneratorExpressionDAGChecker.h"
#include "cmMakefile.h"
//----------------------------------------------------------------------------
cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
const cmListFileBacktrace &backtrace,
const std::string &target,
const std::string &property,
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *parent)
: Parent(parent), Target(target), Property(property),
Content(content), Backtrace(backtrace)
{
this->IsDAG = this->isDAG();
}
//----------------------------------------------------------------------------
bool cmGeneratorExpressionDAGChecker::check() const
{
return this->IsDAG;
}
//----------------------------------------------------------------------------
void cmGeneratorExpressionDAGChecker::reportError(
cmGeneratorExpressionContext *context,
const std::string &expr)
{
if (this->IsDAG)
{
return;
}
context->HadError = true;
if (context->Quiet)
{
return;
}
const cmGeneratorExpressionDAGChecker *parent = this->Parent;
if (parent && !parent->Parent)
{
cmOStringStream e;
e << "Error evaluating generator expression:\n"
<< " " << expr << "\n"
<< "Self reference on target \""
<< context->Target->GetName() << "\".\n";
context->Makefile->GetCMakeInstance()
->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
parent->Backtrace);
return;
}
{
cmOStringStream e;
e << "Error evaluating generator expression:\n"
<< " " << expr << "\n"
<< "Dependency loop found.";
context->Makefile->GetCMakeInstance()
->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
context->Backtrace);
}
int loopStep = 1;
while (parent)
{
cmOStringStream e;
e << "Loop step " << loopStep << "\n"
<< " "
<< (parent->Content ? parent->Content->GetOriginalExpression() : expr)
<< "\n";
context->Makefile->GetCMakeInstance()
->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
parent->Backtrace);
parent = parent->Parent;
++loopStep;
}
}
//----------------------------------------------------------------------------
bool cmGeneratorExpressionDAGChecker::isDAG() const
{
const cmGeneratorExpressionDAGChecker *parent = this->Parent;
while (parent)
{
if (this->Target == parent->Target && this->Property == parent->Property)
{
return false;
}
parent = parent->Parent;
}
return true;
}

View File

@ -0,0 +1,44 @@
/*============================================================================
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 cmGeneratorExpressionDAGChecker_h
#define cmGeneratorExpressionDAGChecker_h
#include "cmStandardIncludes.h"
#include "cmGeneratorExpressionEvaluator.h"
//----------------------------------------------------------------------------
struct cmGeneratorExpressionDAGChecker
{
cmGeneratorExpressionDAGChecker(const cmListFileBacktrace &backtrace,
const std::string &target,
const std::string &property,
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *parent);
bool check() const;
void reportError(cmGeneratorExpressionContext *context,
const std::string &expr);
private:
bool isDAG() const;
private:
const cmGeneratorExpressionDAGChecker * const Parent;
const std::string Target;
const std::string Property;
const GeneratorExpressionContent * const Content;
const cmListFileBacktrace Backtrace;
bool IsDAG;
};
#endif

View File

@ -13,6 +13,8 @@
#include "cmGeneratorExpressionEvaluator.h"
#include "cmGeneratorExpressionParser.h"
#include "cmGeneratorExpressionDAGChecker.h"
#include "cmGeneratorExpression.h"
//----------------------------------------------------------------------------
static void reportError(cmGeneratorExpressionContext *context,
@ -47,7 +49,8 @@ struct cmGeneratorExpressionNode
virtual std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
const GeneratorExpressionContent *content
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *dagChecker
) const = 0;
};
@ -60,7 +63,8 @@ static const struct ZeroNode : public cmGeneratorExpressionNode
std::string Evaluate(const std::vector<std::string> &,
cmGeneratorExpressionContext *,
const GeneratorExpressionContent *) const
const GeneratorExpressionContent *,
cmGeneratorExpressionDAGChecker *) const
{
// Unreachable
return std::string();
@ -76,7 +80,8 @@ static const struct OneNode : public cmGeneratorExpressionNode
std::string Evaluate(const std::vector<std::string> &,
cmGeneratorExpressionContext *,
const GeneratorExpressionContent *) const
const GeneratorExpressionContent *,
cmGeneratorExpressionDAGChecker *) const
{
// Unreachable
return std::string();
@ -93,7 +98,8 @@ static const struct OP ## Node : public cmGeneratorExpressionNode \
\
std::string Evaluate(const std::vector<std::string> &parameters, \
cmGeneratorExpressionContext *context, \
const GeneratorExpressionContent *content) const \
const GeneratorExpressionContent *content, \
cmGeneratorExpressionDAGChecker *) const \
{ \
std::vector<std::string>::const_iterator it = parameters.begin(); \
const std::vector<std::string>::const_iterator end = parameters.end(); \
@ -123,9 +129,11 @@ BOOLEAN_OP_NODE(orNode, OR, 0, 1)
static const struct NotNode : public cmGeneratorExpressionNode
{
NotNode() {}
std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
const GeneratorExpressionContent *content) const
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *) const
{
if (*parameters.begin() != "0" && *parameters.begin() != "1")
{
@ -137,15 +145,81 @@ static const struct NotNode : public cmGeneratorExpressionNode
}
} notNode;
//----------------------------------------------------------------------------
static const struct BoolNode : public cmGeneratorExpressionNode
{
BoolNode() {}
virtual int NumExpectedParameters() const { return 1; }
std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *,
const GeneratorExpressionContent *,
cmGeneratorExpressionDAGChecker *) const
{
return !cmSystemTools::IsOff(parameters.begin()->c_str()) ? "1" : "0";
}
} boolNode;
//----------------------------------------------------------------------------
static const struct StrEqualNode : public cmGeneratorExpressionNode
{
StrEqualNode() {}
virtual int NumExpectedParameters() const { return 2; }
std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *,
const GeneratorExpressionContent *,
cmGeneratorExpressionDAGChecker *) const
{
return *parameters.begin() == parameters.at(1) ? "1" : "0";
}
} strEqualNode;
//----------------------------------------------------------------------------
static const struct Angle_RNode : public cmGeneratorExpressionNode
{
Angle_RNode() {}
virtual int NumExpectedParameters() const { return 0; }
std::string Evaluate(const std::vector<std::string> &,
cmGeneratorExpressionContext *,
const GeneratorExpressionContent *,
cmGeneratorExpressionDAGChecker *) const
{
return ">";
}
} angle_rNode;
//----------------------------------------------------------------------------
static const struct CommaNode : public cmGeneratorExpressionNode
{
CommaNode() {}
virtual int NumExpectedParameters() const { return 0; }
std::string Evaluate(const std::vector<std::string> &,
cmGeneratorExpressionContext *,
const GeneratorExpressionContent *,
cmGeneratorExpressionDAGChecker *) const
{
return ",";
}
} commaNode;
//----------------------------------------------------------------------------
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
const GeneratorExpressionContent *,
cmGeneratorExpressionDAGChecker *) const
{
return context->Config ? context->Config : "";
}
@ -160,7 +234,8 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
const GeneratorExpressionContent *content) const
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *) const
{
if (!context->Config)
{
@ -179,6 +254,61 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
}
} configurationTestNode;
//----------------------------------------------------------------------------
static const struct TargetPropertyNode : public cmGeneratorExpressionNode
{
TargetPropertyNode() {}
// This node handles errors on parameter count itself.
virtual int NumExpectedParameters() const { return -1; }
std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *dagCheckerParent
) const
{
if (parameters.size() != 1 && parameters.size() != 2)
{
reportError(context, content->GetOriginalExpression(),
"$<TARGET_PROPERTY:...> expression requires one or two parameters");
return std::string();
}
cmGeneratorTarget* target = context->Target;
std::string propertyName = *parameters.begin();
if (parameters.size() == 2)
{
target = context->Makefile->FindGeneratorTargetToUse(
parameters.begin()->c_str());
if (!target)
{
cmOStringStream e;
e << "Target \""
<< target
<< "\" not found.";
reportError(context, content->GetOriginalExpression(), e.str());
}
propertyName = parameters.at(1);
}
cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
target->GetName(),
propertyName,
content,
dagCheckerParent);
if (!dagChecker.check())
{
dagChecker.reportError(context, content->GetOriginalExpression());
return std::string();
}
const char *prop = target->GetProperty(propertyName.c_str());
return prop ? prop : "";
}
} targetPropertyNode;
//----------------------------------------------------------------------------
template<bool linker, bool soname>
struct TargetFilesystemArtifactResultCreator
@ -293,7 +423,8 @@ struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
const GeneratorExpressionContent *content) const
const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *) const
{
// Lookup the referenced target.
std::string name = *parameters.begin();
@ -392,7 +523,18 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
return &targetLinkerFileDirNode;
else if (identifier == "TARGET_SONAME_FILE_DIR")
return &targetSoNameFileDirNode;
else if (identifier == "STREQUAL")
return &strEqualNode;
else if (identifier == "BOOL")
return &boolNode;
else if (identifier == "ANGLE-R")
return &angle_rNode;
else if (identifier == "COMMA")
return &commaNode;
else if (identifier == "TARGET_PROPERTY")
return &targetPropertyNode;
return 0;
}
//----------------------------------------------------------------------------
@ -412,7 +554,8 @@ std::string GeneratorExpressionContent::GetOriginalExpression() const
//----------------------------------------------------------------------------
std::string GeneratorExpressionContent::Evaluate(
cmGeneratorExpressionContext *context) const
cmGeneratorExpressionContext *context,
cmGeneratorExpressionDAGChecker *dagChecker) const
{
std::string identifier;
{
@ -422,7 +565,7 @@ std::string GeneratorExpressionContent::Evaluate(
= this->IdentifierChildren.end();
for ( ; it != end; ++it)
{
identifier += (*it)->Evaluate(context);
identifier += (*it)->Evaluate(context, dagChecker);
if (context->HadError)
{
return std::string();
@ -465,7 +608,7 @@ std::string GeneratorExpressionContent::Evaluate(
= pit->end();
for ( ; it != end; ++it)
{
result += (*it)->Evaluate(context);
result += (*it)->Evaluate(context, dagChecker);
if (context->HadError)
{
return std::string();
@ -491,7 +634,7 @@ std::string GeneratorExpressionContent::Evaluate(
pit->end();
for ( ; it != end; ++it)
{
parameter += (*it)->Evaluate(context);
parameter += (*it)->Evaluate(context, dagChecker);
if (context->HadError)
{
return std::string();
@ -534,7 +677,7 @@ std::string GeneratorExpressionContent::Evaluate(
return std::string();
}
return node->Evaluate(parameters, context, this);
return node->Evaluate(parameters, context, this, dagChecker);
}
//----------------------------------------------------------------------------

View File

@ -15,6 +15,11 @@
#include <vector>
#include <string>
#include "cmListFileCache.h"
class cmTarget;
class cmGeneratorTarget;
//----------------------------------------------------------------------------
struct cmGeneratorExpressionContext
{
@ -22,11 +27,13 @@ struct cmGeneratorExpressionContext
std::set<cmTarget*> Targets;
cmMakefile *Makefile;
const char *Config;
cmTarget *Target;
cmGeneratorTarget *Target;
bool Quiet;
bool HadError;
};
struct cmGeneratorExpressionDAGChecker;
//----------------------------------------------------------------------------
struct cmGeneratorExpressionEvaluator
{
@ -41,8 +48,8 @@ struct cmGeneratorExpressionEvaluator
virtual Type GetType() const = 0;
virtual std::string Evaluate(cmGeneratorExpressionContext *context
) const = 0;
virtual std::string Evaluate(cmGeneratorExpressionContext *context,
cmGeneratorExpressionDAGChecker *) const = 0;
private:
cmGeneratorExpressionEvaluator(const cmGeneratorExpressionEvaluator &);
@ -57,7 +64,8 @@ struct TextContent : public cmGeneratorExpressionEvaluator
}
std::string Evaluate(cmGeneratorExpressionContext *) const
std::string Evaluate(cmGeneratorExpressionContext *,
cmGeneratorExpressionDAGChecker *) const
{
return std::string(this->Content, this->Length);
}
@ -102,7 +110,8 @@ struct GeneratorExpressionContent : public cmGeneratorExpressionEvaluator
return cmGeneratorExpressionEvaluator::Generator;
}
std::string Evaluate(cmGeneratorExpressionContext *context) const;
std::string Evaluate(cmGeneratorExpressionContext *context,
cmGeneratorExpressionDAGChecker *) const;
std::string GetOriginalExpression() const;

View File

@ -17,6 +17,8 @@
#include "cmComputeLinkInformation.h"
#include "cmGlobalGenerator.h"
#include "cmSourceFile.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorExpressionDAGChecker.h"
#include <assert.h>
@ -289,19 +291,40 @@ std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories()
{
std::vector<std::string> includes;
const char *prop = this->Target->GetProperty("INCLUDE_DIRECTORIES");
if(prop)
if(!prop)
{
cmSystemTools::ExpandListArgument(prop, includes);
return includes;
}
const char *config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE");
cmListFileBacktrace lfbt;
cmGeneratorExpression ge(lfbt);
cmGeneratorExpressionDAGChecker dagChecker(lfbt,
this->GetName(),
"INCLUDE_DIRECTORIES", 0, 0);
cmSystemTools::ExpandListArgument(ge.Parse(prop)
.Evaluate(this->Makefile,
config,
false,
this,
&dagChecker),
includes);
std::set<std::string> uniqueIncludes;
std::vector<std::string> orderedAndUniqueIncludes;
for(std::vector<std::string>::const_iterator
li = includes.begin(); li != includes.end(); ++li)
{
if(uniqueIncludes.insert(*li).second)
std::string inc = *li;
if (!cmSystemTools::IsOff(inc.c_str()))
{
orderedAndUniqueIncludes.push_back(*li);
cmSystemTools::ConvertToUnixSlashes(inc);
}
if(uniqueIncludes.insert(inc).second)
{
orderedAndUniqueIncludes.push_back(inc);
}
}
@ -309,15 +332,30 @@ std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories()
}
//----------------------------------------------------------------------------
const char *cmGeneratorTarget::GetCompileDefinitions(const char *config)
std::string cmGeneratorTarget::GetCompileDefinitions(const char *config)
{
if (!config)
std::string defPropName = "COMPILE_DEFINITIONS";
if (config)
{
return this->Target->GetProperty("COMPILE_DEFINITIONS");
defPropName += "_" + cmSystemTools::UpperCase(config);
}
std::string defPropName = "COMPILE_DEFINITIONS_";
defPropName +=
cmSystemTools::UpperCase(config);
return this->Target->GetProperty(defPropName.c_str());
const char *prop = this->Target->GetProperty(defPropName.c_str());
if (!prop)
{
return "";
}
cmListFileBacktrace lfbt;
cmGeneratorExpression ge(lfbt);
cmGeneratorExpressionDAGChecker dagChecker(lfbt,
this->GetName(),
defPropName, 0, 0);
return ge.Parse(prop).Evaluate(this->Makefile,
config,
false,
this,
&dagChecker);
}

View File

@ -74,7 +74,7 @@ public:
/** Get the include directories for this target. */
std::vector<std::string> GetIncludeDirectories();
const char *GetCompileDefinitions(const char *config = 0);
std::string GetCompileDefinitions(const char *config = 0);
private:
void ClassifySources();

View File

@ -1647,16 +1647,12 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
// Add the export symbol definition for shared library objects.
this->AppendDefines(ppDefs, exportMacro);
}
this->AppendDefines
(ppDefs, this->CurrentMakefile->GetProperty("COMPILE_DEFINITIONS"));
this->AppendDefines(ppDefs, target.GetProperty("COMPILE_DEFINITIONS"));
cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&target);
this->AppendDefines(ppDefs, gtgt->GetCompileDefinitions().c_str());
if(configName)
{
std::string defVarName = "COMPILE_DEFINITIONS_";
defVarName += cmSystemTools::UpperCase(configName);
this->AppendDefines
(ppDefs, this->CurrentMakefile->GetProperty(defVarName.c_str()));
this->AppendDefines(ppDefs, target.GetProperty(defVarName.c_str()));
this->AppendDefines(ppDefs,
gtgt->GetCompileDefinitions(configName).c_str());
}
buildSettings->AddAttribute
("GCC_PREPROCESSOR_DEFINITIONS", ppDefs.CreateList());
@ -1713,10 +1709,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
// Set target-specific architectures.
std::vector<std::string> archs;
{
cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&target);
gtgt->GetAppleArchs(configName, archs);
}
if(!archs.empty())
{
// Enable ARCHS attribute.
@ -1953,7 +1947,6 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
BuildObjectListOrString dirs(this, this->XcodeVersion >= 30);
BuildObjectListOrString fdirs(this, this->XcodeVersion >= 30);
std::vector<std::string> includes;
cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&target);
this->CurrentLocalGenerator->GetIncludeDirectories(includes, gtgt);
std::set<cmStdString> emitted;
emitted.insert("/System/Library/Frameworks");

View File

@ -55,6 +55,11 @@ bool cmIncludeDirectoryCommand
return true;
}
static bool StartsWithGeneratorExpression(const std::string &input)
{
return input[0] == '$' && input[1] == '<';
}
// do a lot of cleanup on the arguments because this is one place where folks
// sometimes take the output of a program and pass it directly into this
// command not thinking that a single argument could be filled with spaces
@ -105,10 +110,13 @@ void cmIncludeDirectoryCommand::AddDirectory(const char *i,
cmSystemTools::ConvertToUnixSlashes(ret);
if(!cmSystemTools::FileIsFullPath(ret.c_str()))
{
std::string tmp = this->Makefile->GetStartDirectory();
tmp += "/";
tmp += ret;
ret = tmp;
if(!StartsWithGeneratorExpression(ret))
{
std::string tmp = this->Makefile->GetStartDirectory();
tmp += "/";
tmp += ret;
ret = tmp;
}
}
}
this->Makefile->AddIncludeDirectory(ret.c_str(), before);

View File

@ -1390,6 +1390,11 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
}
}
if(!target)
{
return;
}
// Load implicit include directories for this language.
std::string impDirVar = "CMAKE_";
impDirVar += lang;
@ -1407,10 +1412,8 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
// Get the target-specific include directories.
std::vector<std::string> includes;
if(target)
{
includes = target->GetIncludeDirectories();
}
includes = target->GetIncludeDirectories();
// Support putting all the in-project include directories first if
// it is requested by the project.

View File

@ -157,6 +157,11 @@ public:
*/
void AppendDefines(std::set<std::string>& defines,
const char* defines_list);
void AppendDefines(std::set<std::string>& defines,
std::string defines_list)
{
this->AppendDefines(defines, defines_list.c_str());
}
/**
* Join a set of defines into a definesString with a space separator.
*/

View File

@ -724,10 +724,6 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
flags += targetFlags;
}
std::string configUpper = cmSystemTools::UpperCase(configName);
std::string defPropName = "COMPILE_DEFINITIONS_";
defPropName += configUpper;
// Get preprocessor definitions for this directory.
std::string defineFlags = this->Makefile->GetDefineFlags();
Options::Tool t = Options::Compiler;
@ -744,11 +740,10 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
targetOptions.Parse(flags.c_str());
targetOptions.Parse(defineFlags.c_str());
targetOptions.ParseFinish();
targetOptions.AddDefines
(this->Makefile->GetProperty("COMPILE_DEFINITIONS"));
targetOptions.AddDefines(target.GetProperty("COMPILE_DEFINITIONS"));
targetOptions.AddDefines(this->Makefile->GetProperty(defPropName.c_str()));
targetOptions.AddDefines(target.GetProperty(defPropName.c_str()));
cmGeneratorTarget* gt =
this->GlobalGenerator->GetGeneratorTarget(&target);
targetOptions.AddDefines(gt->GetCompileDefinitions().c_str());
targetOptions.AddDefines(gt->GetCompileDefinitions(configName).c_str());
targetOptions.SetVerboseMakefile(
this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
@ -819,8 +814,6 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
targetOptions.OutputAdditionalOptions(fout, "\t\t\t\t", "\n");
fout << "\t\t\t\tAdditionalIncludeDirectories=\"";
std::vector<std::string> includes;
cmGeneratorTarget* gt =
this->GlobalGenerator->GetGeneratorTarget(&target);
this->GetIncludeDirectories(includes, gt);
std::vector<std::string>::iterator i = includes.begin();
for(;i != includes.end(); ++i)

View File

@ -1225,21 +1225,16 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
flags += " ";
flags += targetFlags;
}
std::string configUpper = cmSystemTools::UpperCase(configName);
std::string defPropName = "COMPILE_DEFINITIONS_";
defPropName += configUpper;
// Get preprocessor definitions for this directory.
std::string defineFlags = this->Target->GetMakefile()->GetDefineFlags();
clOptions.FixExceptionHandlingDefault();
clOptions.AddFlag("PrecompiledHeader", "NotUsing");
clOptions.Parse(flags.c_str());
clOptions.Parse(defineFlags.c_str());
clOptions.AddDefines
(this->Makefile->GetProperty("COMPILE_DEFINITIONS"));
clOptions.AddDefines(this->Target->GetProperty("COMPILE_DEFINITIONS"));
clOptions.AddDefines(this->Makefile->GetProperty(defPropName.c_str()));
clOptions.AddDefines(this->Target->GetProperty(defPropName.c_str()));
clOptions.AddDefines(
this->GeneratorTarget->GetCompileDefinitions().c_str());
clOptions.AddDefines(this->GeneratorTarget->GetCompileDefinitions(
configName.c_str()).c_str());
clOptions.SetVerboseMakefile(
this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));

View File

@ -27,6 +27,15 @@ enum {
#endif
};
#ifdef TEST_GENERATOR_EXPRESSIONS
#ifndef CMAKE_IS_DECLARATIVE
#error Expect declarative definition
#endif
#ifdef GE_NOT_DEFINED
#error Expect not defined generator expression
#endif
#endif
int main(int argc, char **argv)
{
return 0;

View File

@ -7,3 +7,9 @@ set_target_properties(target_prop_executable PROPERTIES COMPILE_DEFINITIONS CMAK
set_property(TARGET target_prop_executable APPEND PROPERTY COMPILE_DEFINITIONS CMAKE_IS_REALLY="Very Fun" CMAKE_IS=Fun)
set_property(TARGET target_prop_executable APPEND PROPERTY COMPILE_DEFINITIONS CMAKE_IS_FUN CMAKE_IS_="Fun")
set_property(TARGET target_prop_executable APPEND PROPERTY COMPILE_DEFINITIONS
TEST_GENERATOR_EXPRESSIONS
"$<1:CMAKE_IS_DECLARATIVE>"
"$<0:GE_NOT_DEFINED>"
)

View File

@ -22,6 +22,23 @@ add_custom_target(check ALL
-Dtest_or_1=$<OR:1>
-Dtest_or_1_0=$<OR:1,0>
-Dtest_or_1_1=$<OR:1,1>
-Dtest_bool_notfound=$<BOOL:NOTFOUND>
-Dtest_bool_foo_notfound=$<BOOL:Foo-NOTFOUND>
-Dtest_bool_true=$<BOOL:True>
-Dtest_bool_false=$<BOOL:False>
-Dtest_bool_on=$<BOOL:On>
-Dtest_bool_off=$<BOOL:Off>
-Dtest_bool_no=$<BOOL:No>
-Dtest_bool_n=$<BOOL:N>
-Dtest_strequal_yes_yes=$<STREQUAL:Yes,Yes>
-Dtest_strequal_yes_yes_cs=$<STREQUAL:Yes,yes>
-Dtest_strequal_yes_no=$<STREQUAL:Yes,No>
-Dtest_strequal_no_yes=$<STREQUAL:No,Yes>
-Dtest_strequal_angle_r=$<STREQUAL:$<ANGLE-R>,$<ANGLE-R>>
-Dtest_strequal_comma=$<STREQUAL:$<COMMA>,$<COMMA>>
-Dtest_strequal_angle_r_comma=$<STREQUAL:$<ANGLE-R>,$<COMMA>>
-Dtest_angle_r=$<ANGLE-R>
-Dtest_comma=$<COMMA>
-P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake
COMMAND ${CMAKE_COMMAND} -E echo "check done"
VERBATIM

View File

@ -23,3 +23,20 @@ check(test_or_0_1 "1")
check(test_or_1 "1")
check(test_or_1_0 "1")
check(test_or_1_1 "1")
check(test_bool_notfound "0")
check(test_bool_foo_notfound "0")
check(test_bool_true "1")
check(test_bool_false "0")
check(test_bool_on "1")
check(test_bool_off "0")
check(test_bool_no "0")
check(test_bool_n "0")
check(test_strequal_yes_yes "1")
check(test_strequal_yes_yes_cs "0")
check(test_strequal_yes_no "0")
check(test_strequal_no_yes "0")
check(test_strequal_angle_r "1")
check(test_strequal_comma "1")
check(test_strequal_angle_r_comma "0")
check(test_angle_r ">")
check(test_comma ",")

View File

@ -12,13 +12,21 @@ create_header(bar)
create_header(bat)
create_header(foo)
create_header(baz)
create_header(bang)
create_header(bing)
create_header(bung)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories("${CMAKE_CURRENT_BINARY_DIR}/bar")
include_directories("$<1:${CMAKE_CURRENT_BINARY_DIR}/bang>")
add_executable(TargetIncludeDirectories main.cpp)
set_property(TARGET TargetIncludeDirectories APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/bat")
set_property(TARGET TargetIncludeDirectories APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/foo")
set_property(TARGET TargetIncludeDirectories APPEND PROPERTY
INCLUDE_DIRECTORIES "$<1:${CMAKE_CURRENT_BINARY_DIR}/bing>")
include_directories("${CMAKE_CURRENT_BINARY_DIR}/baz")
include_directories("$<1:${CMAKE_CURRENT_BINARY_DIR}/bung>")
include_directories("sing$<1:/ting>")

View File

@ -3,6 +3,10 @@
#include "bat.h"
#include "foo.h"
#include "baz.h"
#include "bang.h"
#include "bing.h"
#include "bung.h"
#include "ting.h"
int main(int, char**)
{

View File

@ -0,0 +1 @@
//ting.h

View File

@ -46,6 +46,7 @@ macro(add_RunCMake_test test)
endmacro()
add_RunCMake_test(GeneratorExpression)
add_RunCMake_test(TargetPropertyGeneratorExpressions)
add_RunCMake_test(Languages)
add_RunCMake_test(ObjectLibrary)

View File

@ -0,0 +1,6 @@
CMake Error:
Error evaluating generator expression:
\$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>
Self reference on target "TargetPropertyGeneratorExpressions".$

View File

@ -0,0 +1,7 @@
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
"int main(int, char **) { return 0; }\n")
add_executable(TargetPropertyGeneratorExpressions
"${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
include_directories("$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>")

View File

@ -0,0 +1,6 @@
CMake Error:
Error evaluating generator expression:
\$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>
Self reference on target "TargetPropertyGeneratorExpressions".$

View File

@ -0,0 +1,9 @@
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
"int main(int, char **) { return 0; }\n")
add_executable(TargetPropertyGeneratorExpressions
"${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
set_property(TARGET TargetPropertyGeneratorExpressions PROPERTY
INCLUDE_DIRECTORIES "$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>"
)

View File

@ -0,0 +1,6 @@
CMake Error:
Error evaluating generator expression:
\$<TARGET_PROPERTY:TargetPropertyGeneratorExpressions,INCLUDE_DIRECTORIES>
Self reference on target "TargetPropertyGeneratorExpressions".$

View File

@ -0,0 +1,8 @@
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
"int main(int, char **) { return 0; }\n")
add_executable(TargetPropertyGeneratorExpressions
"${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
include_directories(
"$<TARGET_PROPERTY:TargetPropertyGeneratorExpressions,INCLUDE_DIRECTORIES>")

View File

@ -0,0 +1,6 @@
CMake Error:
Error evaluating generator expression:
\$<TARGET_PROPERTY:TargetPropertyGeneratorExpressions,INCLUDE_DIRECTORIES>
Self reference on target "TargetPropertyGeneratorExpressions".$

View File

@ -0,0 +1,10 @@
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
"int main(int, char **) { return 0; }\n")
add_executable(TargetPropertyGeneratorExpressions
"${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
set_property(TARGET TargetPropertyGeneratorExpressions PROPERTY
INCLUDE_DIRECTORIES
"$<TARGET_PROPERTY:TargetPropertyGeneratorExpressions,INCLUDE_DIRECTORIES>"
)

View File

@ -0,0 +1,6 @@
CMake Error:
Error evaluating generator expression:
\$<TARGET_PROPERTY:COMPILE_DEFINITIONS>
Self reference on target "TargetPropertyGeneratorExpressions".$

View File

@ -0,0 +1,10 @@
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
"int main(int, char **) { return 0; }\n")
add_executable(TargetPropertyGeneratorExpressions
"${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
set_property(TARGET TargetPropertyGeneratorExpressions
PROPERTY
COMPILE_DEFINITIONS "$<TARGET_PROPERTY:COMPILE_DEFINITIONS>"
)

View File

@ -0,0 +1,6 @@
CMake Error:
Error evaluating generator expression:
\$<TARGET_PROPERTY:TargetPropertyGeneratorExpressions,COMPILE_DEFINITIONS>
Self reference on target "TargetPropertyGeneratorExpressions".$

View File

@ -0,0 +1,10 @@
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
"int main(int, char **) { return 0; }\n")
add_executable(TargetPropertyGeneratorExpressions
"${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
set_property(TARGET TargetPropertyGeneratorExpressions PROPERTY
COMPILE_DEFINITIONS
"$<TARGET_PROPERTY:TargetPropertyGeneratorExpressions,COMPILE_DEFINITIONS>"
)

View File

@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 2.8)
project(${RunCMake_TEST} CXX)
# MSVC creates extra targets which pollute the stderr unless we set this.
set(CMAKE_SUPPRESS_REGENERATION TRUE)
include(${RunCMake_TEST}.cmake)

View File

@ -0,0 +1,8 @@
include(RunCMake)
run_cmake(BadSelfReference1)
run_cmake(BadSelfReference2)
run_cmake(BadSelfReference3)
run_cmake(BadSelfReference4)
run_cmake(BadSelfReference5)
run_cmake(BadSelfReference6)

View File

@ -202,6 +202,7 @@ CMAKE_CXX_SOURCES="\
cmInstallDirectoryGenerator \
cmGeneratedFileStream \
cmGeneratorTarget \
cmGeneratorExpressionDAGChecker \
cmGeneratorExpressionEvaluator \
cmGeneratorExpressionLexer \
cmGeneratorExpressionParser \