diff options
author | Brad King <brad.king@kitware.com> | 2012-09-28 21:15:03 (GMT) |
---|---|---|
committer | CMake Topic Stage <kwrobot@kitware.com> | 2012-09-28 21:15:03 (GMT) |
commit | 103d99338a11b7e35c9a1a9382e56aa3d43c468d (patch) | |
tree | 51811cff589bab5929202d07c1cf969eaae889e6 /Source | |
parent | 908f46a161683ed2cb0de61eb54f74ae665511ef (diff) | |
parent | 083de7ed35b26dceff6edeb4fc8f9d2500855a9b (diff) | |
download | CMake-103d99338a11b7e35c9a1a9382e56aa3d43c468d.zip CMake-103d99338a11b7e35c9a1a9382e56aa3d43c468d.tar.gz CMake-103d99338a11b7e35c9a1a9382e56aa3d43c468d.tar.bz2 |
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.
Diffstat (limited to 'Source')
-rw-r--r-- | Source/CMakeLists.txt | 2 | ||||
-rw-r--r-- | Source/cmAddTestCommand.h | 2 | ||||
-rw-r--r-- | Source/cmDocumentGeneratorExpressions.h | 17 | ||||
-rw-r--r-- | Source/cmExtraCodeBlocksGenerator.cxx | 93 | ||||
-rw-r--r-- | Source/cmGeneratorExpression.cxx | 8 | ||||
-rw-r--r-- | Source/cmGeneratorExpression.h | 12 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionDAGChecker.cxx | 106 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionDAGChecker.h | 44 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionEvaluator.cxx | 169 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionEvaluator.h | 19 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.cxx | 60 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.h | 2 | ||||
-rw-r--r-- | Source/cmGlobalXCodeGenerator.cxx | 17 | ||||
-rw-r--r-- | Source/cmIncludeDirectoryCommand.cxx | 16 | ||||
-rw-r--r-- | Source/cmLocalGenerator.cxx | 11 | ||||
-rw-r--r-- | Source/cmLocalGenerator.h | 5 | ||||
-rw-r--r-- | Source/cmLocalVisualStudio7Generator.cxx | 15 | ||||
-rw-r--r-- | Source/cmVisualStudio10TargetGenerator.cxx | 13 |
18 files changed, 490 insertions, 121 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 354f123..5a3e7d1 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -183,6 +183,8 @@ set(SRCS cmFileTimeComparison.cxx cmFileTimeComparison.h cmGeneratedFileStream.cxx + cmGeneratorExpressionDAGChecker.cxx + cmGeneratorExpressionDAGChecker.h cmGeneratorExpressionEvaluator.cxx cmGeneratorExpressionEvaluator.h cmGeneratorExpressionLexer.cxx diff --git a/Source/cmAddTestCommand.h b/Source/cmAddTestCommand.h index b11bff9..6a0cd9d 100644 --- a/Source/cmAddTestCommand.h +++ b/Source/cmAddTestCommand.h @@ -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" diff --git a/Source/cmDocumentGeneratorExpressions.h b/Source/cmDocumentGeneratorExpressions.h index 74c673a..6b0cf49 100644 --- a/Source/cmDocumentGeneratorExpressions.h +++ b/Source/cmDocumentGeneratorExpressions.h @@ -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 diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index b1bbd90..8b2daba 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -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; + + 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); + } - 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::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"; + for(std::set<std::string>::const_iterator dirIt=uniqIncludeDirs.begin(); + dirIt != uniqIncludeDirs.end(); + ++dirIt) + { + fout <<" <Add directory=\"" << dirIt->c_str() << "\" />\n"; } - else // e.g. all and the GLOBAL and UTILITY targets + + fout<<" </Compiler>\n"; + } + else // e.g. all and the GLOBAL and UTILITY targets { fout<<" <Option working_dir=\"" << makefile->GetStartOutputDirectory() << "\" />\n" diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 0885616..3f8e962 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -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 = ""; diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index b8467c2..d37ce97 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -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 diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx new file mode 100644 index 0000000..bfb0ddf --- /dev/null +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -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; +} diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h new file mode 100644 index 0000000..ffc84f8 --- /dev/null +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -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 diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 9f84ed2..22f60d4 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -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> ¶meters, 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> ¶meters, \ 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> ¶meters, cmGeneratorExpressionContext *context, - const GeneratorExpressionContent *content) const + const GeneratorExpressionContent *content, + cmGeneratorExpressionDAGChecker *) const { if (*parameters.begin() != "0" && *parameters.begin() != "1") { @@ -138,14 +146,80 @@ 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> ¶meters, + 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> ¶meters, + 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> ¶meters, cmGeneratorExpressionContext *context, - const GeneratorExpressionContent *content) const + const GeneratorExpressionContent *content, + cmGeneratorExpressionDAGChecker *) const { if (!context->Config) { @@ -180,6 +255,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> ¶meters, + 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> ¶meters, 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); } //---------------------------------------------------------------------------- diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h index 5163ca0..04a2acd 100644 --- a/Source/cmGeneratorExpressionEvaluator.h +++ b/Source/cmGeneratorExpressionEvaluator.h @@ -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; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 91f16d1..d4b57f4 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -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())) + { + cmSystemTools::ConvertToUnixSlashes(inc); + } + if(uniqueIncludes.insert(inc).second) { - orderedAndUniqueIncludes.push_back(*li); + 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); } diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 4487c11..8ea17d7 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -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(); diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 39b0ffe..95c6807 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -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"); diff --git a/Source/cmIncludeDirectoryCommand.cxx b/Source/cmIncludeDirectoryCommand.cxx index 4dd98a1..ba81849 100644 --- a/Source/cmIncludeDirectoryCommand.cxx +++ b/Source/cmIncludeDirectoryCommand.cxx @@ -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); diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index d452658..6079ba8 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -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. diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 0916d44..9aaacf7 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -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. */ diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 2ededfe..11d9d9c 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -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) diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index fea117a..90718ab 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -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")); |