diff options
author | Brad King <brad.king@kitware.com> | 2013-02-05 19:46:43 (GMT) |
---|---|---|
committer | CMake Topic Stage <kwrobot@kitware.com> | 2013-02-05 19:46:43 (GMT) |
commit | ec85306025ae787e08d4ce097fde966f1809c74f (patch) | |
tree | b583e726d1ab08212554cf299bb653604c72ff2a | |
parent | 020525845a3999078e4f7897d293c5aeab20af87 (diff) | |
parent | e48d84209cde93b43fcfb305897b4f52cd18a55f (diff) | |
download | CMake-ec85306025ae787e08d4ce097fde966f1809c74f.zip CMake-ec85306025ae787e08d4ce097fde966f1809c74f.tar.gz CMake-ec85306025ae787e08d4ce097fde966f1809c74f.tar.bz2 |
Merge topic 'tll-includes-defines'
e48d842 Cache context-independent includes on evaluation.
089fe1c Optimize genex evaluation for includes and defines.
179f495 find_package: Reword <package>_NO_INTERFACES documentation
e7b579b Test workaround of bad interface include directories from depends.
77cecb7 Add includes and compile definitions with target_link_libraries.
0b92602 Add the $<LINKED:...> generator expression.
0fa7f69 Add API to check if we're reading a includes or defines property.
2c3654c Add a way to exclude INTERFACE properties from exported targets.
d4297d5 Export targets to a targets file, not a Config file.
df4d2b2 Make it an error for INSTALL_PREFIX to be evaluated.
7ceeba9 Advance more when preprocessing exported strings.
30268b4 Handle reading empty properties defined by the link interface.
41 files changed, 633 insertions, 94 deletions
diff --git a/Source/cmDocumentGeneratorExpressions.h b/Source/cmDocumentGeneratorExpressions.h index 8b80a8a..3993f7d 100644 --- a/Source/cmDocumentGeneratorExpressions.h +++ b/Source/cmDocumentGeneratorExpressions.h @@ -51,6 +51,14 @@ "on the target tgt.\n" \ "Note that tgt is not added as a dependency of the target this " \ "expression is evaluated on.\n" \ + " $<LINKED:item> = An empty string if item is not a " \ + "target. If item is a target then the " \ + "INTERFACE_INCLUDE_DIRECTORIES or INTERFACE_COMPILE_DEFINITIONS " \ + "content is read from the target. " \ + "This generator expression can only be used in evaluation of the " \ + "INCLUDE_DIRECTORIES or COMPILE_DEFINITIONS property. Note that " \ + "this expression is for internal use and may be changed or removed " \ + "in the future.\n" \ " $<TARGET_POLICY:pol> = '1' if the policy was NEW when " \ "the 'head' target was created, else '0'. If the policy was not " \ "set, the warning message for the policy will be emitted. This " \ diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index dbe64e9..7e4c3df 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -25,6 +25,8 @@ #include <cmsys/auto_ptr.hxx> +#include "assert.h" + //---------------------------------------------------------------------------- cmExportFileGenerator::cmExportFileGenerator() { @@ -160,7 +162,7 @@ void cmExportFileGenerator::PopulateInterfaceProperty(const char *propName, preprocessRule); if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, target, + this->ResolveTargetsInGeneratorExpressions(prepro, target, propName, missingTargets); properties[outputName] = prepro; } @@ -264,15 +266,16 @@ void cmExportFileGenerator::GenerateInterfaceProperties(cmTarget *target, { if (!properties.empty()) { + os << "if(NOT ${CMAKE_FIND_PACKAGE_NAME}_NO_INTERFACES)\n"; std::string targetName = this->Namespace; targetName += target->GetName(); - os << "set_target_properties(" << targetName << " PROPERTIES\n"; + os << " set_target_properties(" << targetName << " PROPERTIES\n"; for(ImportPropertyMap::const_iterator pi = properties.begin(); pi != properties.end(); ++pi) { - os << " " << pi->first << " \"" << pi->second << "\"\n"; + os << " " << pi->first << " \"" << pi->second << "\"\n"; } - os << ")\n\n"; + os << " )\nendif()\n\n"; } } @@ -323,13 +326,14 @@ static bool isGeneratorExpression(const std::string &lib) void cmExportFileGenerator::ResolveTargetsInGeneratorExpressions( std::string &input, - cmTarget* target, + cmTarget* target, const char *propName, std::vector<std::string> &missingTargets, FreeTargetsReplace replace) { if (replace == NoReplaceFreeTargets) { - this->ResolveTargetsInGeneratorExpression(input, target, missingTargets); + this->ResolveTargetsInGeneratorExpression(input, target, propName, + missingTargets); return; } std::vector<std::string> parts; @@ -348,7 +352,7 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpressions( { this->ResolveTargetsInGeneratorExpression( *li, - target, + target, propName, missingTargets); } input += sep + *li; @@ -360,7 +364,7 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpressions( void cmExportFileGenerator::ResolveTargetsInGeneratorExpression( std::string &input, - cmTarget* target, + cmTarget* target, const char *propName, std::vector<std::string> &missingTargets) { std::string::size_type pos = 0; @@ -391,12 +395,63 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpression( { input.replace(nameStartPos, commaPos - nameStartPos, targetName); } - lastPos = pos + targetName.size(); + lastPos = nameStartPos + targetName.size() + 1; } std::string errorString; pos = 0; lastPos = pos; + while((pos = input.find("$<LINKED:", lastPos)) != input.npos) + { + std::string::size_type nameStartPos = pos + sizeof("$<LINKED:") - 1; + std::string::size_type endPos = input.find(">", nameStartPos); + if (endPos == input.npos) + { + errorString = "$<LINKED:...> expression incomplete"; + break; + } + std::string targetName = input.substr(nameStartPos, + endPos - nameStartPos); + if(targetName.find("$<") != input.npos) + { + errorString = "$<LINKED:...> requires its parameter to be a " + "literal."; + break; + } + if (this->AddTargetNamespace(targetName, target, missingTargets)) + { + assert(propName); // The link libraries strings will + // never contain $<LINKED> + std::string replacement = "$<TARGET_PROPERTY:" + + targetName + "," + propName; + input.replace(pos, endPos - pos, replacement); + lastPos = pos + replacement.size() + 1; + } + else + { + if (pos != 0) + { + if (input[pos - 1] == ';') + { + --pos; + } + } + else if (input[endPos + 1] == ';') + { + ++endPos; + } + input.replace(pos, endPos - pos + 1, ""); + lastPos = pos; + } + } + if (!errorString.empty()) + { + mf->IssueMessage(cmake::FATAL_ERROR, errorString); + return; + } + + pos = 0; + lastPos = pos; while((pos = input.find("$<TARGET_NAME:", lastPos)) != input.npos) { std::string::size_type nameStartPos = pos + sizeof("$<TARGET_NAME:") - 1; @@ -490,7 +545,7 @@ cmExportFileGenerator preprocessRule); if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions(prepro, target, + this->ResolveTargetsInGeneratorExpressions(prepro, target, 0, missingTargets, ReplaceFreeTargets); properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = prepro; diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 776be61..5ad27bf 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -119,7 +119,7 @@ protected: }; void ResolveTargetsInGeneratorExpressions(std::string &input, - cmTarget* target, + cmTarget* target, const char *propName, std::vector<std::string> &missingTargets, FreeTargetsReplace replace = NoReplaceFreeTargets); @@ -150,7 +150,7 @@ private: std::vector<std::string> &missingTargets); void ResolveTargetsInGeneratorExpression(std::string &input, - cmTarget* target, + cmTarget* target, const char *propName, std::vector<std::string> &missingTargets); virtual void ReplaceInstallPrefix(std::string &input); diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 470ceca..6e78bd7 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -376,6 +376,26 @@ void cmFindPackageCommand::GenerateDocumentation() "The package configuration file may set <package>_FOUND to false " "to tell find_package that component requirements are not satisfied." "\n" + "A package configuration file may include() a <package>Targets.cmake " + "file, created by install(EXPORT) in the upstream source, to import " + "targets into the downstream consumer. " + "When a new version of the upstream adds INTERFACE properties not " + "present in a previous version it can change behavior for existing " + "downstreams. " + "In order to remain source compatible the upstream package configuration " + "file may set <package>_NO_INTERFACES to disable INTERFACE properties. " + "For example, code of the form:\n" + " if(<package>_FIND_VERSION VERSION_LESS <new-version>\n" + " AND NOT <package>_INTERFACES)\n" + " set(<package>_NO_INTERFACES 1)\n" + " endif()\n" + " include(\"${CMAKE_CURRENT_LIST_DIR}/<package>Targets.cmake\")\n" + "tells <package>Targets.cmake not to provide the INTERFACE properties " + "unless the downstream requests at least <new-version> or sets " + "<package>_INTERFACES to explicitly request them. " + "This allows consumers to decide when to enable the new interfaces when " + "upgrading." + "\n" "See the cmake_policy() command documentation for discussion of the " "NO_POLICY_SCOPE option." ; diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 78ae8f2..7add1bf 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -88,6 +88,7 @@ const char *cmCompiledGeneratorExpression::Evaluate( context.Config = config; context.Quiet = quiet; context.HadError = false; + context.HadContextSensitiveCondition = false; context.HeadTarget = headTarget; context.CurrentTarget = currentTarget ? currentTarget : headTarget; context.Backtrace = this->Backtrace; @@ -109,6 +110,10 @@ const char *cmCompiledGeneratorExpression::Evaluate( break; } } + if (!context.HadError) + { + this->HadContextSensitiveCondition = context.HadContextSensitiveCondition; + } this->Targets = context.Targets; // TODO: Return a std::string from here instead? @@ -118,7 +123,8 @@ const char *cmCompiledGeneratorExpression::Evaluate( cmCompiledGeneratorExpression::cmCompiledGeneratorExpression( cmListFileBacktrace const& backtrace, const char *input) - : Backtrace(backtrace), Input(input ? input : "") + : Backtrace(backtrace), Input(input ? input : ""), + HadContextSensitiveCondition(false) { cmGeneratorExpressionLexer l; std::vector<cmGeneratorExpressionToken> tokens = diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index 8f1aef6..700fe03 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -100,6 +100,10 @@ public: { return this->Backtrace; } + bool GetHadContextSensitiveCondition() const + { + return this->HadContextSensitiveCondition; + } private: cmCompiledGeneratorExpression(cmListFileBacktrace const& backtrace, @@ -118,6 +122,7 @@ private: mutable std::set<cmTarget*> Targets; mutable std::map<cmStdString, cmStdString> SeenTargetProperties; mutable std::string Output; + mutable bool HadContextSensitiveCondition; }; #endif diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index 269211b..b9069ef 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -24,7 +24,33 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker( : Parent(parent), Target(target), Property(property), Content(content), Backtrace(backtrace) { + const cmGeneratorExpressionDAGChecker *top = this; + const cmGeneratorExpressionDAGChecker *p = this->Parent; + while (p) + { + top = p; + p = p->Parent; + } this->CheckResult = this->checkGraph(); + + if (CheckResult == DAG && (top->Property == "INCLUDE_DIRECTORIES" + || top->Property == "COMPILE_DEFINITIONS") ) + { + std::map<cmStdString, std::set<cmStdString> >::const_iterator it + = top->Seen.find(target); + if (it != top->Seen.end()) + { + const std::set<cmStdString> &propSet = it->second; + const std::set<cmStdString>::const_iterator i = propSet.find(property); + if (i != propSet.end()) + { + this->CheckResult = ALREADY_SEEN; + return; + } + } + const_cast<cmGeneratorExpressionDAGChecker *>(top) + ->Seen[target].insert(property); + } } //---------------------------------------------------------------------------- @@ -125,3 +151,19 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries() || strncmp(prop, "LINK_INTERFACE_LIBRARIES_", 26) == 0 || strncmp(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_", 35) == 0); } + +//---------------------------------------------------------------------------- +bool cmGeneratorExpressionDAGChecker::EvaluatingIncludeDirectories() +{ + const char *prop = this->Property.c_str(); + return (strcmp(prop, "INCLUDE_DIRECTORIES") == 0 + || strcmp(prop, "INTERFACE_INCLUDE_DIRECTORIES") == 0 ); +} + +//---------------------------------------------------------------------------- +bool cmGeneratorExpressionDAGChecker::EvaluatingCompileDefinitions() +{ + const char *prop = this->Property.c_str(); + return (strcmp(prop, "COMPILE_DEFINITIONS") == 0 + || strcmp(prop, "INTERFACE_COMPILE_DEFINITIONS") == 0 ); +} diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index 3169291..a2e5ce4 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -28,7 +28,8 @@ struct cmGeneratorExpressionDAGChecker enum Result { DAG, SELF_REFERENCE, - CYCLIC_REFERENCE + CYCLIC_REFERENCE, + ALREADY_SEEN }; Result check() const; @@ -37,6 +38,8 @@ struct cmGeneratorExpressionDAGChecker const std::string &expr); bool EvaluatingLinkLibraries(); + bool EvaluatingIncludeDirectories(); + bool EvaluatingCompileDefinitions(); private: Result checkGraph() const; @@ -45,6 +48,7 @@ private: const cmGeneratorExpressionDAGChecker * const Parent; const std::string Target; const std::string Property; + std::map<cmStdString, std::set<cmStdString> > Seen; const GeneratorExpressionContent * const Content; const cmListFileBacktrace Backtrace; Result CheckResult; diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index f74b69e..5d94718 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -238,6 +238,7 @@ static const struct ConfigurationNode : public cmGeneratorExpressionNode const GeneratorExpressionContent *, cmGeneratorExpressionDAGChecker *) const { + context->HadContextSensitiveCondition = true; return context->Config ? context->Config : ""; } } configurationNode; @@ -262,6 +263,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode "Expression syntax not recognized."); return std::string(); } + context->HadContextSensitiveCondition = true; if (!context->Config) { return parameters.front().empty() ? "1" : "0"; @@ -435,6 +437,9 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: // No error. We just skip cyclic references. return std::string(); + case cmGeneratorExpressionDAGChecker::ALREADY_SEEN: + // No error. We're not going to find anything new here. + return std::string(); case cmGeneratorExpressionDAGChecker::DAG: break; } @@ -452,12 +457,14 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode } if (propertyName == "POSITION_INDEPENDENT_CODE") { + context->HadContextSensitiveCondition = true; return target->GetLinkInterfaceDependentBoolProperty( "POSITION_INDEPENDENT_CODE", context->Config) ? "1" : "0"; } if (target->IsLinkInterfaceDependentBoolProperty(propertyName, context->Config)) { + context->HadContextSensitiveCondition = true; return target->GetLinkInterfaceDependentBoolProperty( propertyName, context->Config) ? "1" : "0"; @@ -465,9 +472,12 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode if (target->IsLinkInterfaceDependentStringProperty(propertyName, context->Config)) { - return target->GetLinkInterfaceDependentStringProperty( + context->HadContextSensitiveCondition = true; + const char *propContent = + target->GetLinkInterfaceDependentStringProperty( propertyName, context->Config); + return propContent ? propContent : ""; } return std::string(); @@ -481,12 +491,19 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode if (targetPropertyTransitiveWhitelist[i] == propertyName) { cmGeneratorExpression ge(context->Backtrace); - return ge.Parse(prop)->Evaluate(context->Makefile, + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop); + std::string result = cge->Evaluate(context->Makefile, context->Config, context->Quiet, context->HeadTarget, target, &dagChecker); + + if (cge->GetHadContextSensitiveCondition()) + { + context->HadContextSensitiveCondition = true; + } + return result; } } return prop; @@ -580,6 +597,9 @@ static const struct TargetPolicyNode : public cmGeneratorExpressionNode "be used with add_custom_command."); return std::string(); } + + context->HadContextSensitiveCondition = true; + for (size_t i = 0; i < (sizeof(targetPolicyWhitelist) / sizeof(*targetPolicyWhitelist)); @@ -619,20 +639,115 @@ static const struct InstallPrefixNode : public cmGeneratorExpressionNode { InstallPrefixNode() {} - virtual bool GeneratesContent() const { return false; } + virtual bool GeneratesContent() const { return true; } virtual int NumExpectedParameters() const { return 0; } std::string Evaluate(const std::vector<std::string> &, - cmGeneratorExpressionContext *, - const GeneratorExpressionContent *, + cmGeneratorExpressionContext *context, + const GeneratorExpressionContent *content, cmGeneratorExpressionDAGChecker *) const { + reportError(context, content->GetOriginalExpression(), + "INSTALL_PREFIX is a marker for install(EXPORT) only. It " + "should never be evaluated."); return std::string(); } } installPrefixNode; //---------------------------------------------------------------------------- +static const struct LinkedNode : public cmGeneratorExpressionNode +{ + LinkedNode() {} + + virtual bool GeneratesContent() const { return true; } + virtual int NumExpectedParameters() const { return 1; } + virtual bool RequiresLiteralInput() const { return true; } + + std::string Evaluate(const std::vector<std::string> ¶meters, + cmGeneratorExpressionContext *context, + const GeneratorExpressionContent *content, + cmGeneratorExpressionDAGChecker *dagChecker) const + { + if (dagChecker->EvaluatingIncludeDirectories()) + { + return this->GetInterfaceProperty(parameters.front(), + "INCLUDE_DIRECTORIES", + context, content, dagChecker); + } + if (dagChecker->EvaluatingCompileDefinitions()) + { + return this->GetInterfaceProperty(parameters.front(), + "COMPILE_DEFINITIONS", + context, content, dagChecker); + } + + reportError(context, content->GetOriginalExpression(), + "$<LINKED:...> may only be used in INCLUDE_DIRECTORIES and " + "COMPILE_DEFINITIONS properties."); + + return std::string(); + } + +private: + std::string GetInterfaceProperty(const std::string &item, + const std::string &prop, + cmGeneratorExpressionContext *context, + const GeneratorExpressionContent *content, + cmGeneratorExpressionDAGChecker *dagCheckerParent) const + { + cmTarget *target = context->CurrentTarget + ->GetMakefile()->FindTargetToUse(item.c_str()); + if (!target) + { + return std::string(); + } + std::string propertyName = "INTERFACE_" + prop; + const char *propContent = target->GetProperty(propertyName.c_str()); + if (!propContent) + { + return std::string(); + } + + cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, + target->GetName(), + propertyName, + content, + dagCheckerParent); + + switch (dagChecker.check()) + { + case cmGeneratorExpressionDAGChecker::SELF_REFERENCE: + dagChecker.reportError(context, content->GetOriginalExpression()); + return std::string(); + case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: + // No error. We just skip cyclic references. + return std::string(); + case cmGeneratorExpressionDAGChecker::ALREADY_SEEN: + // No error. We're not going to find anything new here. + return std::string(); + case cmGeneratorExpressionDAGChecker::DAG: + break; + } + + cmGeneratorExpression ge(context->Backtrace); + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(propContent); + std::string result = cge->Evaluate(context->Makefile, + context->Config, + context->Quiet, + context->HeadTarget, + target, + &dagChecker); + if (cge->GetHadContextSensitiveCondition()) + { + context->HadContextSensitiveCondition = true; + } + return result; + } + +} linkedNode; + +//---------------------------------------------------------------------------- template<bool linker, bool soname> struct TargetFilesystemArtifactResultCreator { @@ -869,6 +984,8 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier) return &targetDefinedNode; else if (identifier == "INSTALL_PREFIX") return &installPrefixNode; + else if (identifier == "LINKED") + return &linkedNode; return 0; } diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h index fb6c7ee..37d5c86 100644 --- a/Source/cmGeneratorExpressionEvaluator.h +++ b/Source/cmGeneratorExpressionEvaluator.h @@ -32,6 +32,7 @@ struct cmGeneratorExpressionContext // directly or indirectly in the property. bool Quiet; bool HadError; + bool HadContextSensitiveCondition; }; struct cmGeneratorExpressionDAGChecker; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 132154c..ca0e24b 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -134,6 +134,7 @@ public: : ge(cge) {} const cmsys::auto_ptr<cmCompiledGeneratorExpression> ge; + std::vector<std::string> CachedIncludes; }; std::vector<IncludeDirectoriesEntry*> IncludeDirectoriesEntries; }; @@ -2778,22 +2779,36 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config) end = this->Internal->IncludeDirectoriesEntries.end(); it != end; ++it) { - std::vector<std::string> entryIncludes; - cmSystemTools::ExpandListArgument((*it)->ge->Evaluate(this->Makefile, - config, - false, - this, - &dagChecker), - entryIncludes); + + bool testIsOff = true; + bool cacheIncludes = false; + std::vector<std::string> entryIncludes = (*it)->CachedIncludes; + if(!entryIncludes.empty()) + { + testIsOff = false; + } + else + { + cmSystemTools::ExpandListArgument((*it)->ge->Evaluate(this->Makefile, + config, + false, + this, + &dagChecker), + entryIncludes); + if (!(*it)->ge->GetHadContextSensitiveCondition()) + { + cacheIncludes = true; + } + } std::string usedIncludes; - for(std::vector<std::string>::const_iterator + for(std::vector<std::string>::iterator li = entryIncludes.begin(); li != entryIncludes.end(); ++li) { - std::string inc = *li; - if (!cmSystemTools::IsOff(inc.c_str())) + if (testIsOff && !cmSystemTools::IsOff(li->c_str())) { - cmSystemTools::ConvertToUnixSlashes(inc); + cmSystemTools::ConvertToUnixSlashes(*li); } + std::string inc = *li; if(uniqueIncludes.insert(inc).second) { @@ -2804,6 +2819,10 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config) } } } + if (cacheIncludes) + { + (*it)->CachedIncludes = entryIncludes; + } if (!usedIncludes.empty()) { this->Makefile->GetCMakeInstance()->IssueMessage(cmake::LOG, diff --git a/Source/cmTarget.h b/Source/cmTarget.h index cf2d4c4..7577a59 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -514,6 +514,9 @@ public: const char *GetLinkInterfaceDependentStringProperty(const std::string &p, const char *config); + + std::string GetDebugGeneratorExpressions(const std::string &value, + cmTarget::LinkLibraryType llt); private: /** * A list of direct dependencies. Use in conjunction with DependencyMap. @@ -659,9 +662,6 @@ private: void ProcessSourceExpression(std::string const& expr); - std::string GetDebugGeneratorExpressions(const std::string &value, - cmTarget::LinkLibraryType llt); - // The cmMakefile instance that owns this target. This should // always be set. cmMakefile* Makefile; diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index f42b0f6..cb913f5 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -250,10 +250,51 @@ cmTargetLinkLibrariesCommand } //---------------------------------------------------------------------------- +static std::string compileProperty(cmTarget *tgt, const std::string &lib, + bool isGenex, + const std::string &property, + cmTarget::LinkLibraryType llt) +{ + std::string value = !isGenex ? "$<LINKED:" + lib + ">" + : "$<$<TARGET_DEFINED:" + lib + ">:" + + "$<TARGET_PROPERTY:" + lib + + ",INTERFACE_" + property + ">" + ">"; + + return tgt->GetDebugGeneratorExpressions(value, llt); +} + +//---------------------------------------------------------------------------- +static bool isGeneratorExpression(const std::string &lib) +{ + const std::string::size_type openpos = lib.find("$<"); + return (openpos != std::string::npos) + && (lib.find(">", openpos) != std::string::npos); +} + +//---------------------------------------------------------------------------- void cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib, cmTarget::LinkLibraryType llt) { + const bool isGenex = isGeneratorExpression(lib); + + cmsys::RegularExpression targetNameValidator; + targetNameValidator.compile("^[A-Za-z0-9_.:-]+$"); + const bool potentialTargetName = targetNameValidator.find(lib); + + if (potentialTargetName || isGenex) + { + this->Target->AppendProperty("INCLUDE_DIRECTORIES", + compileProperty(this->Target, lib, + isGenex, + "INCLUDE_DIRECTORIES", llt).c_str()); + this->Target->AppendProperty("COMPILE_DEFINITIONS", + compileProperty(this->Target, lib, + isGenex, + "COMPILE_DEFINITIONS", llt).c_str()); + } + // Handle normal case first. if(this->CurrentProcessingState != ProcessingLinkInterface) { @@ -266,6 +307,18 @@ cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib, } } + if (potentialTargetName || isGenex) + { + this->Target->AppendProperty("INTERFACE_COMPILE_DEFINITIONS", + compileProperty(this->Target, lib, + isGenex, + "COMPILE_DEFINITIONS", llt).c_str()); + this->Target->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES", + compileProperty(this->Target, lib, + isGenex, + "INCLUDE_DIRECTORIES", llt).c_str()); + } + // Get the list of configurations considered to be DEBUG. std::vector<std::string> const& debugConfigs = this->Makefile->GetCMakeInstance()->GetDebugConfigs(); diff --git a/Source/cmTargetLinkLibrariesCommand.h b/Source/cmTargetLinkLibrariesCommand.h index 3da3950..aaabdfa 100644 --- a/Source/cmTargetLinkLibrariesCommand.h +++ b/Source/cmTargetLinkLibrariesCommand.h @@ -97,6 +97,15 @@ public: "Calls to other signatures of this command may set the property " "making any libraries linked exclusively by this signature private." "\n" + "Target usage requirements are also consumed by this command. If the " + "<target> is linked to another target which has " + "a populated INTERFACE_INCLUDE_DIRECTORIES, the content of it is " + "appended to the INCLUDE_DIRECTORIES of <target>. Similarly, the " + "INTERFACE_COMPILE_DEFINITONS of a dependee are added to the " + "COMPILE_DEFINITONS of <target>, and the " + "INTERFACE_POSITION_INDEPENDENT_CODE property is used to determine the " + "POSITION_INDEPENDENT_CODE property of <target>." + "\n" " target_link_libraries(<target> LINK_INTERFACE_LIBRARIES\n" " [[debug|optimized|general] <lib>] ...)\n" "The LINK_INTERFACE_LIBRARIES mode appends the libraries " diff --git a/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt b/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt index 8a4437b..0bfcc1b 100644 --- a/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt +++ b/Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt @@ -16,9 +16,15 @@ add_executable(consumer "${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp" ) +add_library(linked UNKNOWN IMPORTED) +set_property(TARGET linked PROPERTY + INTERFACE_COMPILE_DEFINITIONS "MY_LINKED_DEFINE") + + target_compile_definitions(consumer PRIVATE $<TARGET_PROPERTY:target_compile_definitions,INTERFACE_COMPILE_DEFINITIONS> $<$<TARGET_DEFINED:notdefined>:SHOULD_NOT_BE_DEFINED> $<$<TARGET_DEFINED:target_compile_definitions>:SHOULD_BE_DEFINED> + $<LINKED:linked> -DDASH_D_DEFINE ) diff --git a/Tests/CMakeCommands/target_compile_definitions/consumer.cpp b/Tests/CMakeCommands/target_compile_definitions/consumer.cpp index 1a46aa5..c077593 100644 --- a/Tests/CMakeCommands/target_compile_definitions/consumer.cpp +++ b/Tests/CMakeCommands/target_compile_definitions/consumer.cpp @@ -23,4 +23,8 @@ #error Expected DASH_D_DEFINE #endif +#ifndef MY_LINKED_DEFINE +#error Expected MY_LINKED_DEFINE +#endif + int main() { return 0; } diff --git a/Tests/CMakeCommands/target_include_directories/CMakeLists.txt b/Tests/CMakeCommands/target_include_directories/CMakeLists.txt index 7529283..a564918 100644 --- a/Tests/CMakeCommands/target_include_directories/CMakeLists.txt +++ b/Tests/CMakeCommands/target_include_directories/CMakeLists.txt @@ -17,6 +17,9 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/poison/common.h" "#error Should not be i file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/cure") file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cure/common.h" "#define CURE_DEFINE\n") +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/linkedinclude") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/linkedinclude/linkedinclude.h" "#define LINKEDINCLUDE_DEFINE\n") + add_executable(target_include_directories "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" ) @@ -42,7 +45,13 @@ add_executable(consumer "${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp" ) +add_library(linked UNKNOWN IMPORTED) +set_property(TARGET linked PROPERTY + INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/linkedinclude") + target_include_directories(consumer - PRIVATE $<TARGET_PROPERTY:target_include_directories,INTERFACE_INCLUDE_DIRECTORIES> + PRIVATE + $<TARGET_PROPERTY:target_include_directories,INTERFACE_INCLUDE_DIRECTORIES> + $<LINKED:linked> relative_dir ) diff --git a/Tests/CMakeCommands/target_include_directories/consumer.cpp b/Tests/CMakeCommands/target_include_directories/consumer.cpp index 82b800a..ccffd9c 100644 --- a/Tests/CMakeCommands/target_include_directories/consumer.cpp +++ b/Tests/CMakeCommands/target_include_directories/consumer.cpp @@ -3,6 +3,7 @@ #include "publicinclude.h" #include "interfaceinclude.h" #include "relative_dir.h" +#include "linkedinclude.h" #ifdef PRIVATEINCLUDE_DEFINE #error Unexpected PRIVATEINCLUDE_DEFINE @@ -24,4 +25,8 @@ #error Expected RELATIVE_DIR_DEFINE #endif +#ifndef LINKEDINCLUDE_DEFINE +#error Expected LINKEDINCLUDE_DEFINE +#endif + int main() { return 0; } diff --git a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt index 1d0e342..cd0fe11 100644 --- a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt +++ b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt @@ -62,10 +62,6 @@ assert_property(targetA LINK_INTERFACE_LIBRARIES "") add_subdirectory(subdir) target_link_libraries(targetA subdirlib) -set_property(TARGET targetA APPEND PROPERTY - INCLUDE_DIRECTORIES - $<TARGET_PROPERTY:subdirlib,INTERFACE_INCLUDE_DIRECTORIES> -) target_link_libraries(targetA depB depC) @@ -87,3 +83,24 @@ set_property(TARGET depD APPEND PROPERTY add_executable(targetB targetB.cpp) target_link_libraries(targetB depD) + +macro(create_header _name) + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${_name}") + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_name}/${_name}.h" "//${_name}.h\n") +endmacro() + +create_header(foo) +create_header(bar) + +add_library(depG SHARED depG.cpp) +generate_export_header(depG) +target_include_directories(depG INTERFACE + "${CMAKE_CURRENT_BINARY_DIR}/foo" + "${CMAKE_CURRENT_BINARY_DIR}/bar" +) +target_compile_definitions(depG INTERFACE + TEST_DEF +) + +add_executable(targetC targetC.cpp) +target_link_libraries(targetC depG) diff --git a/Tests/CMakeCommands/target_link_libraries/depG.cpp b/Tests/CMakeCommands/target_link_libraries/depG.cpp new file mode 100644 index 0000000..65b9655 --- /dev/null +++ b/Tests/CMakeCommands/target_link_libraries/depG.cpp @@ -0,0 +1,7 @@ + +#include "depG.h" + +int DepG::foo() +{ + return 0; +} diff --git a/Tests/CMakeCommands/target_link_libraries/depG.h b/Tests/CMakeCommands/target_link_libraries/depG.h new file mode 100644 index 0000000..1a36589 --- /dev/null +++ b/Tests/CMakeCommands/target_link_libraries/depG.h @@ -0,0 +1,7 @@ + +#include "depg_export.h" + +struct DEPG_EXPORT DepG +{ + int foo(); +}; diff --git a/Tests/CMakeCommands/target_link_libraries/targetC.cpp b/Tests/CMakeCommands/target_link_libraries/targetC.cpp new file mode 100644 index 0000000..ff6ba66 --- /dev/null +++ b/Tests/CMakeCommands/target_link_libraries/targetC.cpp @@ -0,0 +1,16 @@ + +#include "depG.h" + +#include "foo.h" +#include "bar.h" + +#ifndef TEST_DEF +#error Expected TEST_DEF definition +#endif + +int main(int argc, char **argv) +{ + DepG g; + + return g.foo(); +} diff --git a/Tests/CompatibleInterface/CMakeLists.txt b/Tests/CompatibleInterface/CMakeLists.txt index 259b5a1..329510b 100644 --- a/Tests/CompatibleInterface/CMakeLists.txt +++ b/Tests/CompatibleInterface/CMakeLists.txt @@ -48,10 +48,22 @@ target_compile_definitions(CompatibleInterface add_library(iface2 SHARED iface2.cpp) generate_export_header(iface2) +set_property(TARGET iface2 APPEND PROPERTY + COMPATIBLE_INTERFACE_STRING + Iface2_PROP +) + # For the LINK_LIBRARIES and related properties, we should not evaluate # properties defined only in the interface - they should be implicitly zero set_property(TARGET iface2 APPEND PROPERTY LINK_INTERFACE_LIBRARIES $<$<BOOL:$<TARGET_PROPERTY:BOOL_PROP4>>:nonexistant> ) -target_link_libraries(CompatibleInterface iface2) +target_link_libraries(CompatibleInterface iface2 + $<$<BOOL:$<TARGET_PROPERTY:Iface2_PROP>>:nonexistant> +) +# Test that this does not segfault: +target_compile_definitions(CompatibleInterface + PRIVATE + $<$<BOOL:$<TARGET_PROPERTY:Iface2_PROP>>:SOME_DEFINE> +) diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt index 47521d8..ae938cd 100644 --- a/Tests/ExportImport/Export/CMakeLists.txt +++ b/Tests/ExportImport/Export/CMakeLists.txt @@ -90,23 +90,7 @@ set_property(TARGET testLibCycleA PROPERTY LINK_INTERFACE_MULTIPLICITY 3) # Test exporting dependent libraries into different exports add_library(testLibRequired testLibRequired.c) add_library(testLibDepends testLibDepends.c) -set_property(TARGET testLibDepends APPEND PROPERTY - INCLUDE_DIRECTORIES - $<TARGET_PROPERTY:testLibRequired,INTERFACE_INCLUDE_DIRECTORIES> -) -set_property(TARGET testLibDepends APPEND PROPERTY - COMPILE_DEFINITIONS - $<TARGET_PROPERTY:testLibRequired,INTERFACE_COMPILE_DEFINITIONS> -) -set_property(TARGET testLibDepends APPEND PROPERTY - INTERFACE_INCLUDE_DIRECTORIES - $<TARGET_PROPERTY:testLibRequired,INTERFACE_INCLUDE_DIRECTORIES> -) -set_property(TARGET testLibDepends APPEND PROPERTY - INTERFACE_COMPILE_DEFINITIONS - $<TARGET_PROPERTY:testLibRequired,INTERFACE_COMPILE_DEFINITIONS> -) -target_link_libraries(testLibDepends testLibRequired) +target_link_libraries(testLibDepends LINK_PUBLIC testLibRequired) macro(add_include_lib _libName) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_libName}.c" "// no content\n") @@ -234,11 +218,30 @@ install(TARGETS testLibRequired testLibIncludeRequired6 testSharedLibRequired EXPORT RequiredExp DESTINATION lib ) -install(EXPORT RequiredExp NAMESPACE Req:: FILE testLibRequiredConfig.cmake DESTINATION lib/cmake/testLibRequired) +install(EXPORT RequiredExp NAMESPACE Req:: FILE testLibRequiredTargets.cmake DESTINATION lib/cmake/testLibRequired) install(TARGETS testLibDepends testSharedLibDepends EXPORT DependsExp DESTINATION lib ) -install(EXPORT DependsExp FILE testLibDependsConfig.cmake DESTINATION lib/cmake/testLibDepends) +install(EXPORT DependsExp FILE testLibDependsTargets.cmake DESTINATION lib/cmake/testLibDepends) +file(WRITE + "${CMAKE_CURRENT_BINARY_DIR}/testLibRequiredConfig.cmake" + " +if(\${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION VERSION_LESS 2.3 AND NOT \${CMAKE_FIND_PACKAGE_NAME}_INTERFACES) + set(\${CMAKE_FIND_PACKAGE_NAME}_NO_INTERFACES 1) +endif() +include(\"\${CMAKE_CURRENT_LIST_DIR}/testLibRequiredTargets.cmake\") +set(\${CMAKE_FIND_PACKAGE_NAME}_INCLUDE_DIRS \"${CMAKE_CURRENT_BINARY_DIR}\" \"${CMAKE_CURRENT_SOURCE_DIR}\" ) +" +) + +include(CMakePackageConfigHelpers) +write_basic_package_version_file( testLibRequiredConfigVersion.cmake VERSION 2.5 COMPATIBILITY AnyNewerVersion) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/testLibRequiredConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/testLibRequiredConfigVersion.cmake" + DESTINATION lib/cmake/testLibRequired +) # Install and export from install tree. install( diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt index e9bd2ba..0337130 100644 --- a/Tests/ExportImport/Import/A/CMakeLists.txt +++ b/Tests/ExportImport/Import/A/CMakeLists.txt @@ -5,8 +5,8 @@ include(${Import_BINARY_DIR}/../Export/ExportBuildTree.cmake) include(${CMAKE_INSTALL_PREFIX}/lib/exp/exp.cmake) # Import two exports, where the Depends one depends on an exported target from the Required one: -include(${CMAKE_INSTALL_PREFIX}/lib/cmake/testLibRequired/testLibRequiredConfig.cmake) -include(${CMAKE_INSTALL_PREFIX}/lib/cmake/testLibDepends/testLibDependsConfig.cmake) +include(${CMAKE_INSTALL_PREFIX}/lib/cmake/testLibRequired/testLibRequiredTargets.cmake) +include(${CMAKE_INSTALL_PREFIX}/lib/cmake/testLibDepends/testLibDependsTargets.cmake) # Try referencing an executable imported from the install tree. add_custom_command( @@ -159,18 +159,11 @@ endif() add_executable(deps_iface deps_iface.c) target_link_libraries(deps_iface testLibDepends) -target_include_directories(deps_iface PRIVATE $<TARGET_PROPERTY:testLibDepends,INTERFACE_INCLUDE_DIRECTORIES>) -target_compile_definitions(deps_iface PRIVATE $<TARGET_PROPERTY:testLibDepends,INTERFACE_COMPILE_DEFINITIONS>) add_executable(deps_shared_iface deps_shared_iface.cpp) target_link_libraries(deps_shared_iface testSharedLibDepends) -target_include_directories(deps_shared_iface - PRIVATE - $<TARGET_PROPERTY:testSharedLibDepends,INTERFACE_INCLUDE_DIRECTORIES> -) target_compile_definitions(deps_shared_iface PRIVATE - $<TARGET_PROPERTY:testSharedLibDepends,INTERFACE_COMPILE_DEFINITIONS> $<$<BOOL:$<TARGET_PROPERTY:POSITION_INDEPENDENT_CODE>>:PIC_PROPERTY_IS_ON> $<$<BOOL:$<TARGET_PROPERTY:CUSTOM_PROP>>:CUSTOM_PROPERTY_IS_ON> $<$<STREQUAL:$<TARGET_PROPERTY:CUSTOM_STRING>,testcontent>:CUSTOM_STRING_IS_MATCH> @@ -200,13 +193,8 @@ endif() add_executable(deps_shared_iface2 deps_shared_iface.cpp) target_link_libraries(deps_shared_iface2 bld_testSharedLibDepends bld_subdirlib) -target_include_directories(deps_shared_iface2 - PRIVATE - $<TARGET_PROPERTY:bld_testSharedLibDepends,INTERFACE_INCLUDE_DIRECTORIES> - $<TARGET_PROPERTY:bld_subdirlib,INTERFACE_INCLUDE_DIRECTORIES> -) target_compile_definitions(deps_shared_iface2 - PRIVATE $<TARGET_PROPERTY:bld_testSharedLibDepends,INTERFACE_COMPILE_DEFINITIONS> TEST_SUBDIR_LIB + PRIVATE TEST_SUBDIR_LIB $<$<BOOL:$<TARGET_PROPERTY:POSITION_INDEPENDENT_CODE>>:PIC_PROPERTY_IS_ON> $<$<BOOL:$<TARGET_PROPERTY:CUSTOM_PROP>>:CUSTOM_PROPERTY_IS_ON> $<$<STREQUAL:$<TARGET_PROPERTY:CUSTOM_STRING>,testcontent>:CUSTOM_STRING_IS_MATCH> diff --git a/Tests/ExportImport/Import/CMakeLists.txt b/Tests/ExportImport/Import/CMakeLists.txt index 3fc78a2..237f8fa 100644 --- a/Tests/ExportImport/Import/CMakeLists.txt +++ b/Tests/ExportImport/Import/CMakeLists.txt @@ -17,3 +17,8 @@ add_executable(imp_testTransExe1 imp_testTransExe1.c) target_link_libraries(imp_testTransExe1 imp_lib1) add_executable(imp_testTransExe1b imp_testTransExe1.c) target_link_libraries(imp_testTransExe1b imp_lib1b) + +# Test package INTERFACE controls +add_subdirectory(package_old_old) +add_subdirectory(package_new_old) +add_subdirectory(package_new_new) diff --git a/Tests/ExportImport/Import/package_new_new/CMakeLists.txt b/Tests/ExportImport/Import/package_new_new/CMakeLists.txt new file mode 100644 index 0000000..4e6f642 --- /dev/null +++ b/Tests/ExportImport/Import/package_new_new/CMakeLists.txt @@ -0,0 +1,23 @@ + +cmake_minimum_required(VERSION 2.8) + +find_package(testLibRequired 2.5 REQUIRED) + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp" + " +#include \"testSharedLibRequired.h\" +int main(int argc, char **argv) +{ + TestSharedLibRequired req; + return req.foo(); +} +" +) + +get_target_property(prop Req::testSharedLibRequired INTERFACE_INCLUDE_DIRECTORIES) +if (NOT prop) + message(SEND_ERROR "Interface of Req::testSharedLibRequired should not be empty") +endif() + +add_executable(new_new_test "${CMAKE_CURRENT_BINARY_DIR}/main.cpp") +target_link_libraries(new_new_test Req::testSharedLibRequired) diff --git a/Tests/ExportImport/Import/package_new_old/CMakeLists.txt b/Tests/ExportImport/Import/package_new_old/CMakeLists.txt new file mode 100644 index 0000000..e675d64 --- /dev/null +++ b/Tests/ExportImport/Import/package_new_old/CMakeLists.txt @@ -0,0 +1,24 @@ + +cmake_minimum_required(VERSION 2.8) + +find_package(testLibRequired 2.5 REQUIRED) + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp" + " +#include \"testSharedLibRequired.h\" +int main(int argc, char **argv) +{ + TestSharedLibRequired req; + return req.foo(); +} +" +) + +get_target_property(prop Req::testSharedLibRequired INTERFACE_INCLUDE_DIRECTORIES) +if ("${prop}" STREQUAL "") + message(SEND_ERROR "Interface of Req::testSharedLibRequired should not be empty") +endif() + +add_executable(new_old_test "${CMAKE_CURRENT_BINARY_DIR}/main.cpp") +target_link_libraries(new_old_test Req::testSharedLibRequired) +include_directories(${testLibRequired_INCLUDE_DIRS}) diff --git a/Tests/ExportImport/Import/package_old_old/CMakeLists.txt b/Tests/ExportImport/Import/package_old_old/CMakeLists.txt new file mode 100644 index 0000000..3b27330 --- /dev/null +++ b/Tests/ExportImport/Import/package_old_old/CMakeLists.txt @@ -0,0 +1,24 @@ + +cmake_minimum_required(VERSION 2.8) + +find_package(testLibRequired 2.1 REQUIRED) + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp" + " +#include \"testSharedLibRequired.h\" +int main(int argc, char **argv) +{ + TestSharedLibRequired req; + return req.foo(); +} +" +) + +get_target_property(prop Req::testSharedLibRequired INTERFACE_INCLUDE_DIRECTORIES) +if (prop) + message(SEND_ERROR "Interface of Req::testSharedLibRequired should be empty, but is ${prop}") +endif() + +add_executable(old_old_test "${CMAKE_CURRENT_BINARY_DIR}/main.cpp") +target_link_libraries(old_old_test Req::testSharedLibRequired) +include_directories(${testLibRequired_INCLUDE_DIRS}) diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt index a40a541..ecbbedf 100644 --- a/Tests/GeneratorExpression/CMakeLists.txt +++ b/Tests/GeneratorExpression/CMakeLists.txt @@ -89,7 +89,6 @@ add_custom_target(check-part2 ALL -Dtest_install_interface=$<INSTALL_INTERFACE:install> -Dtest_target_name_1=$<TARGET_NAME:tgt,ok> -Dtest_target_name_2=$<TARGET_NAME:tgt:ok> - -Dtest_install_prefix=$<INSTALL_PREFIX> -P ${CMAKE_CURRENT_SOURCE_DIR}/check-part2.cmake COMMAND ${CMAKE_COMMAND} -E echo "check done (part 2 of 2)" VERBATIM diff --git a/Tests/GeneratorExpression/check-part2.cmake b/Tests/GeneratorExpression/check-part2.cmake index 0b50204..8855a97 100644 --- a/Tests/GeneratorExpression/check-part2.cmake +++ b/Tests/GeneratorExpression/check-part2.cmake @@ -26,4 +26,3 @@ check(test_build_interface "build") check(test_install_interface "") check(test_target_name_1 "tgt,ok") check(test_target_name_2 "tgt:ok") -check(test_install_prefix "") diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt index 21159e0..5387377 100644 --- a/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt +++ b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt @@ -82,3 +82,44 @@ add_custom_target(test_custom_target $<TARGET_PROPERTY:TargetIncludeDirectories,COMPILE_DEFINITIONS> WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") + +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bad") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/bad/common.h" "#error Should not be included\n") +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/good") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/good/common.h" "#include \"othergood.h\"\n") +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/othergood") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/othergood/othergood.h" "// No error\n") + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/libothergood.cpp" "// No content \n") +add_library(libothergood "${CMAKE_CURRENT_BINARY_DIR}/libothergood.cpp") +set_property(TARGET libothergood APPEND PROPERTY + INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/othergood" +) + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/libgood.cpp" "// No content \n") +add_library(libgood "${CMAKE_CURRENT_BINARY_DIR}/libgood.cpp") +set_property(TARGET libgood APPEND PROPERTY + INTERFACE_INCLUDE_DIRECTORIES + "${CMAKE_CURRENT_BINARY_DIR}/good;$<TARGET_PROPERTY:libothergood,INTERFACE_INCLUDE_DIRECTORIES>" +) + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/libbad.cpp" "// No content \n") +add_library(libbad "${CMAKE_CURRENT_BINARY_DIR}/libbad.cpp") +set_property(TARGET libbad APPEND PROPERTY + INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/bad" +) + + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib5.cpp" "#include \"common.h\"\n") +add_library(lib5 "${CMAKE_CURRENT_BINARY_DIR}/lib5.cpp") + +# Assuming the link order must be: +target_link_libraries(lib5 libbad libgood) + +# Oops!. +# As include directory order and link order are the same when using target_link_libraries, we have to +# get the libgood includes in before the libbad includes. +# We do that with this command: +target_include_directories(lib5 + BEFORE PRIVATE $<LINKED:libgood> +) diff --git a/Tests/Qt4Targets/CMakeLists.txt b/Tests/Qt4Targets/CMakeLists.txt index d3aba74..d0c9c66 100644 --- a/Tests/Qt4Targets/CMakeLists.txt +++ b/Tests/Qt4Targets/CMakeLists.txt @@ -12,29 +12,10 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) add_executable(Qt4Targets WIN32 main.cpp) target_link_libraries(Qt4Targets Qt4::QtGui) -set_property(TARGET Qt4Targets APPEND PROPERTY - INCLUDE_DIRECTORIES - $<TARGET_PROPERTY:Qt4::QtGui,INTERFACE_INCLUDE_DIRECTORIES> -) -set_property(TARGET Qt4Targets APPEND PROPERTY - COMPILE_DEFINITIONS - $<TARGET_PROPERTY:Qt4::QtGui,INTERFACE_COMPILE_DEFINITIONS> -) - if (WIN32) if (TARGET Qt4::QAxServer) add_executable(activeqtexe WIN32 activeqtexe.cpp) set_property(TARGET activeqtexe PROPERTY QT4_NO_LINK_QTMAIN ON) target_link_libraries(activeqtexe Qt4::QAxServer Qt4::QtGui) - set_property(TARGET activeqtexe APPEND PROPERTY - INCLUDE_DIRECTORIES - $<TARGET_PROPERTY:Qt4::QAxServer,INTERFACE_INCLUDE_DIRECTORIES> - $<TARGET_PROPERTY:Qt4::QtGui,INTERFACE_INCLUDE_DIRECTORIES> - ) - set_property(TARGET activeqtexe APPEND PROPERTY - COMPILE_DEFINITIONS - $<TARGET_PROPERTY:Qt4::QAxServer,INTERFACE_COMPILE_DEFINITIONS> - $<TARGET_PROPERTY:Qt4::QtGui,INTERFACE_COMPILE_DEFINITIONS> - ) endif() endif() diff --git a/Tests/RunCMake/GeneratorExpression/BadInstallPrefix-result.txt b/Tests/RunCMake/GeneratorExpression/BadInstallPrefix-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/BadInstallPrefix-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GeneratorExpression/BadInstallPrefix-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadInstallPrefix-stderr.txt new file mode 100644 index 0000000..271eb6e --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/BadInstallPrefix-stderr.txt @@ -0,0 +1,9 @@ +CMake Error at BadInstallPrefix.cmake:1 \(add_custom_target\): + Error evaluating generator expression: + + \$<INSTALL_PREFIX> + + INSTALL_PREFIX is a marker for install\(EXPORT\) only. It should never be + evaluated. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/GeneratorExpression/BadInstallPrefix.cmake b/Tests/RunCMake/GeneratorExpression/BadInstallPrefix.cmake new file mode 100644 index 0000000..fcfc3eb --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/BadInstallPrefix.cmake @@ -0,0 +1,3 @@ +add_custom_target(check ALL COMMAND check + $<INSTALL_PREFIX>/include + VERBATIM) diff --git a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake index 8a69675..62bf29b 100644 --- a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake +++ b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake @@ -7,3 +7,4 @@ run_cmake(BadNOT) run_cmake(BadStrEqual) run_cmake(BadZero) run_cmake(BadTargetName) +run_cmake(BadInstallPrefix) diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadLinked-result.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadLinked-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadLinked-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadLinked-stderr.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadLinked-stderr.txt new file mode 100644 index 0000000..4cd9cdd --- /dev/null +++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadLinked-stderr.txt @@ -0,0 +1,7 @@ +CMake Error: + Error evaluating generator expression: + + \$<LINKED:something> + + \$<LINKED:...> may only be used in INCLUDE_DIRECTORIES and + COMPILE_DEFINITIONS properties.$ diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadLinked.cmake b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadLinked.cmake new file mode 100644 index 0000000..542ea76 --- /dev/null +++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadLinked.cmake @@ -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") +target_link_libraries(TargetPropertyGeneratorExpressions "$<LINKED:something>") diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/RunCMakeTest.cmake b/Tests/RunCMake/TargetPropertyGeneratorExpressions/RunCMakeTest.cmake index 0ee3238..ea48f61 100644 --- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/RunCMakeTest.cmake +++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/RunCMakeTest.cmake @@ -15,3 +15,4 @@ run_cmake(BadInvalidName5) run_cmake(BadInvalidName6) run_cmake(BadInvalidName7) run_cmake(BadInvalidName8) +run_cmake(BadLinked) |