From f99196dc0cde6e5868cc74c603a78b10f1ba324a Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Mon, 10 Dec 2012 12:00:34 +0100 Subject: Add cmGeneratorExpression::Split() API. It can split a string like "A;$<1:B>;$<1:C>;D;E;$<1:F;G;H>;$<1:I>;J" into "A" "$<1:B>" "$<1:C>" "D" "E" "$<1:F;G;H>" "$<1:I>" "J" --- Source/cmGeneratorExpression.cxx | 61 ++++++++++++++++++++++++++++++++++++++++ Source/cmGeneratorExpression.h | 3 ++ 2 files changed, 64 insertions(+) diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 4063697..d306dee 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -251,6 +251,67 @@ static std::string stripExportInterface(const std::string &input, } //---------------------------------------------------------------------------- +void cmGeneratorExpression::Split(const std::string &input, + std::vector &output) +{ + std::string::size_type pos = 0; + std::string::size_type lastPos = pos; + while((pos = input.find("$<", lastPos)) != input.npos) + { + std::string part = input.substr(lastPos, pos - lastPos); + std::string preGenex; + if (!part.empty()) + { + std::string::size_type startPos = input.rfind(";", pos); + if (startPos != pos - 1 && startPos >= lastPos) + { + part = input.substr(lastPos, startPos - lastPos); + preGenex = input.substr(startPos + 1, pos - startPos - 1); + } + cmSystemTools::ExpandListArgument(part.c_str(), output); + } + pos += 2; + int nestingLevel = 1; + const char *c = input.c_str() + pos; + const char * const cStart = c; + for ( ; *c; ++c) + { + if(c[0] == '$' && c[1] == '<') + { + ++nestingLevel; + ++c; + continue; + } + if(c[0] == '>') + { + --nestingLevel; + if (nestingLevel == 0) + { + break; + } + } + } + for ( ; *c; ++c) + { + // Capture the part after the genex and before the next ';' + if(c[0] == ';') + { + --c; + break; + } + } + const std::string::size_type traversed = (c - cStart) + 1; + output.push_back(preGenex + "$<" + input.substr(pos, traversed)); + pos += traversed; + lastPos = pos; + } + if (lastPos < input.size()) + { + cmSystemTools::ExpandListArgument(input.substr(lastPos), output); + } +} + +//---------------------------------------------------------------------------- std::string cmGeneratorExpression::Preprocess(const std::string &input, PreprocessContext context) { diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index b58dde5..8f1aef6 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -59,6 +59,9 @@ public: static std::string Preprocess(const std::string &input, PreprocessContext context); + static void Split(const std::string &input, + std::vector &output); + private: cmGeneratorExpression(const cmGeneratorExpression &); void operator=(const cmGeneratorExpression &); -- cgit v0.12 From cb1afbf466d126f233e93b2cdfa3f5c5dfe5b8f7 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Tue, 8 Jan 2013 21:06:24 +0100 Subject: Don't pass a position when determining if a target name is a literal. The lastPos refers to a position in a different string. --- Source/cmExportFileGenerator.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 90c0c41..56b088e 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -270,7 +270,7 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpressions( } const std::string targetName = input.substr(nameStartPos, endPos - nameStartPos); - if(targetName.find("$<", lastPos) != input.npos) + if(targetName.find("$<") != input.npos) { errorString = "$ requires its parameter to be a " "literal."; -- cgit v0.12 From b6036d104a95156e8524dbfeb5533d3a579d8837 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Tue, 8 Jan 2013 20:58:33 +0100 Subject: Extract the AddTargetNamespace method. --- Source/cmExportFileGenerator.cxx | 143 +++++++++++++-------------------------- Source/cmExportFileGenerator.h | 4 ++ 2 files changed, 52 insertions(+), 95 deletions(-) diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 56b088e..da18856 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -184,6 +184,41 @@ void cmExportFileGenerator::GenerateInterfaceProperties(cmTarget *target, } //---------------------------------------------------------------------------- +bool +cmExportFileGenerator::AddTargetNamespace(std::string &input, + cmTarget* target, + std::vector &missingTargets) +{ + cmMakefile *mf = target->GetMakefile(); + + cmTarget *tgt = mf->FindTargetToUse(input.c_str()); + if (!tgt) + { + return false; + } + + if(tgt->IsImported()) + { + return true; + } + if(this->ExportedTargets.find(tgt) != this->ExportedTargets.end()) + { + input = this->Namespace + input; + } + else + { + std::string namespacedTarget; + this->HandleMissingTarget(namespacedTarget, missingTargets, + mf, target, tgt); + if (!namespacedTarget.empty()) + { + input = namespacedTarget; + } + } + return true; +} + +//---------------------------------------------------------------------------- void cmExportFileGenerator::ResolveTargetsInGeneratorExpressions( std::string &input, @@ -212,45 +247,17 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpressions( continue; } - const std::string targetName = input.substr(nameStartPos, + std::string targetName = input.substr(nameStartPos, commaPos - nameStartPos); - pos = nameStartPos; // We're not going to replace the entire expression, - // but only the target parameter. - if (cmTarget *tgt = mf->FindTargetToUse(targetName.c_str())) - { - if(tgt->IsImported()) - { - pos += targetName.size(); - } - else if(this->ExportedTargets.find(tgt) != this->ExportedTargets.end()) - { - input.replace(pos, targetName.size(), - this->Namespace + targetName); - pos += this->Namespace.size() + targetName.size(); - } - else - { - std::string namespacedTarget; - this->HandleMissingTarget(namespacedTarget, missingTargets, - mf, target, tgt); - if (!namespacedTarget.empty()) - { - input.replace(pos, targetName.size(), namespacedTarget); - pos += namespacedTarget.size(); - } - } - } - else + if (!this->AddTargetNamespace(targetName, target, missingTargets)) { errorString = "$ requires " "its first parameter to be a reachable target."; - } - lastPos = pos; - if (!errorString.empty()) - { break; } + input.replace(nameStartPos, commaPos - nameStartPos, targetName); + lastPos = pos + targetName.size(); } if (!errorString.empty()) { @@ -267,51 +274,24 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpressions( if (endPos == input.npos) { errorString = "$ expression incomplete"; + break; } - const std::string targetName = input.substr(nameStartPos, + std::string targetName = input.substr(nameStartPos, endPos - nameStartPos); if(targetName.find("$<") != input.npos) { errorString = "$ requires its parameter to be a " "literal."; + break; } - if (cmTarget *tgt = mf->FindTargetToUse(targetName.c_str())) - { - if(tgt->IsImported()) - { - input.replace(pos, sizeof("$ExportedTargets.find(tgt) != this->ExportedTargets.end()) - { - input.replace(pos, sizeof("$Namespace + targetName); - pos += sizeof("$HandleMissingTarget(namespacedTarget, missingTargets, - mf, target, tgt); - if (!namespacedTarget.empty()) - { - input.replace(pos, sizeof("$AddTargetNamespace(targetName, target, missingTargets)) { errorString = "$ requires its parameter to be a " "reachable target."; - } - lastPos = pos; - if (!errorString.empty()) - { break; } + input.replace(pos, endPos - pos + 1, targetName); + lastPos = endPos; } if (!errorString.empty()) { @@ -397,9 +377,6 @@ cmExportFileGenerator return; } - // Get the makefile in which to lookup target information. - cmMakefile* mf = target->GetMakefile(); - // Construct the property value. std::string link_libs; const char* sep = ""; @@ -410,33 +387,9 @@ cmExportFileGenerator link_libs += sep; sep = ";"; - // Append this entry. - if(cmTarget* tgt = mf->FindTargetToUse(li->c_str())) - { - // This is a target. - if(tgt->IsImported()) - { - // The target is imported (and therefore is not in the - // export). Append the raw name. - link_libs += *li; - } - else if(this->ExportedTargets.find(tgt) != this->ExportedTargets.end()) - { - // The target is in the export. Append it with the export - // namespace. - link_libs += this->Namespace; - link_libs += *li; - } - else - { - this->HandleMissingTarget(link_libs, missingTargets, mf, target, tgt); - } - } - else - { - // Append the raw name. - link_libs += *li; - } + std::string temp = *li; + this->AddTargetNamespace(temp, target, missingTargets); + link_libs += temp; } // Store the property. diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 7c58ad8..a5b25f4 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -128,6 +128,10 @@ private: cmGeneratorExpression::PreprocessContext, ImportPropertyMap &properties, std::vector &missingTargets); + + bool AddTargetNamespace(std::string &input, cmTarget* target, + std::vector &missingTargets); + }; #endif -- cgit v0.12 From a3aedb8152ad6fcdb42fd04e45307eea6ce0043e Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Fri, 4 Jan 2013 15:56:13 +0100 Subject: Split the generator expression before extracting targets. Now that we're processing a LINK_INTERFACE_LIBRARIES string, it can contain targets. Make sure they are extracted for namespacing purposes. This needs to be restricted to strings which can actually have targets named in them. For example, this is not done for INTERFACE_COMPILE_DEFINITIONS, because even if there is a target named 'foo', the string 'foo' in that property means that '-Dfoo' will be set when compiling. --- Source/cmExportFileGenerator.cxx | 45 ++++++++++++++++++++++++++++++++++++++++ Source/cmExportFileGenerator.h | 14 +++++++++++-- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index da18856..df8f3e8 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -219,10 +219,55 @@ cmExportFileGenerator::AddTargetNamespace(std::string &input, } //---------------------------------------------------------------------------- +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 cmExportFileGenerator::ResolveTargetsInGeneratorExpressions( std::string &input, cmTarget* target, + std::vector &missingTargets, + FreeTargetsReplace replace) +{ + if (replace == NoReplaceFreeTargets) + { + this->ResolveTargetsInGeneratorExpression(input, target, missingTargets); + return; + } + std::vector parts; + cmGeneratorExpression::Split(input, parts); + + std::string sep; + input = ""; + for(std::vector::iterator li = parts.begin(); + li != parts.end(); ++li) + { + if (!isGeneratorExpression(*li)) + { + this->AddTargetNamespace(*li, target, missingTargets); + } + else + { + this->ResolveTargetsInGeneratorExpression( + *li, + target, + missingTargets); + } + input += sep + *li; + sep = ";"; + } +} + +//---------------------------------------------------------------------------- +void +cmExportFileGenerator::ResolveTargetsInGeneratorExpression( + std::string &input, + cmTarget* target, std::vector &missingTargets) { std::string::size_type pos = 0; diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index a5b25f4..866806b 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -102,9 +102,16 @@ protected: void GenerateInterfaceProperties(cmTarget *target, std::ostream& os, const ImportPropertyMap &properties); + + enum FreeTargetsReplace { + ReplaceFreeTargets, + NoReplaceFreeTargets + }; + void ResolveTargetsInGeneratorExpressions(std::string &input, - cmTarget* target, - std::vector &missingTargets); + cmTarget* target, + std::vector &missingTargets, + FreeTargetsReplace replace = NoReplaceFreeTargets); // The namespace in which the exports are placed in the generated file. std::string Namespace; @@ -132,6 +139,9 @@ private: bool AddTargetNamespace(std::string &input, cmTarget* target, std::vector &missingTargets); + void ResolveTargetsInGeneratorExpression(std::string &input, + cmTarget* target, + std::vector &missingTargets); }; #endif -- cgit v0.12 From 94aeaf72c714eb184ec61bf6e7bc573bd1bc15c9 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Fri, 4 Jan 2013 15:58:16 +0100 Subject: Split LINK_INTERFACE_LIBRARIES export handling into dedicated method. --- Source/cmExportBuildFileGenerator.cxx | 4 ++++ Source/cmExportFileGenerator.cxx | 24 +++++++++++++++++++++--- Source/cmExportFileGenerator.h | 4 ++++ Source/cmExportInstallFileGenerator.cxx | 4 ++++ 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 9533319..29f6743 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -107,6 +107,10 @@ cmExportBuildFileGenerator std::vector missingTargets; this->SetImportDetailProperties(config, suffix, target, properties, missingTargets); + this->SetImportLinkInterface(config, suffix, + cmGeneratorExpression::BuildInterface, + target, properties, missingTargets); + // TOOD: PUBLIC_HEADER_LOCATION // This should wait until the build feature propagation stuff diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index df8f3e8..5e5f455 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -347,6 +347,26 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpression( //---------------------------------------------------------------------------- void cmExportFileGenerator +::SetImportLinkInterface(const char* config, std::string const& suffix, + cmGeneratorExpression::PreprocessContext preprocessRule, + cmTarget* target, ImportPropertyMap& properties, + std::vector& missingTargets) +{ + // Add the transitive link dependencies for this configuration. + cmTarget::LinkInterface const* iface = target->GetLinkInterface(config, + target); + if (!iface) + { + return; + } + this->SetImportLinkProperty(suffix, target, + "IMPORTED_LINK_INTERFACE_LIBRARIES", + iface->Libraries, properties, missingTargets); +} + +//---------------------------------------------------------------------------- +void +cmExportFileGenerator ::SetImportDetailProperties(const char* config, std::string const& suffix, cmTarget* target, ImportPropertyMap& properties, std::vector& missingTargets @@ -388,9 +408,7 @@ cmExportFileGenerator this->SetImportLinkProperty(suffix, target, "IMPORTED_LINK_INTERFACE_LANGUAGES", iface->Languages, properties, missingTargets); - this->SetImportLinkProperty(suffix, target, - "IMPORTED_LINK_INTERFACE_LIBRARIES", - iface->Libraries, properties, missingTargets); + this->SetImportLinkProperty(suffix, target, "IMPORTED_LINK_DEPENDENT_LIBRARIES", iface->SharedDeps, properties, missingTargets); diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 866806b..4d97a63 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -102,6 +102,10 @@ protected: void GenerateInterfaceProperties(cmTarget *target, std::ostream& os, const ImportPropertyMap &properties); + void SetImportLinkInterface(const char* config, std::string const& suffix, + cmGeneratorExpression::PreprocessContext preprocessRule, + cmTarget* target, ImportPropertyMap& properties, + std::vector& missingTargets); enum FreeTargetsReplace { ReplaceFreeTargets, diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index bc953c9..68881a1 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -229,6 +229,10 @@ cmExportInstallFileGenerator this->SetImportDetailProperties(config, suffix, te->Target, properties, missingTargets); + this->SetImportLinkInterface(config, suffix, + cmGeneratorExpression::InstallInterface, + te->Target, properties, missingTargets); + // TOOD: PUBLIC_HEADER_LOCATION // This should wait until the build feature propagation stuff // is done. Then this can be a propagated include directory. -- cgit v0.12 From 77d26467848fd689fbbffbaa302d041aa2365b15 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Fri, 4 Jan 2013 13:36:18 +0100 Subject: Allow generator expressions in LINK_INTERFACE_LIBRARIES. The Config and IMPORTED_ variants may also contain generator expressions. If 'the implementation is the interface', then the result of evaluating the expressions at generate time is used to populate the IMPORTED_LINK_INTERFACE_LIBRARIES property. 1) In the case of non-static libraries, this is fine because the user still has the option to populate the LINK_INTERFACE_LIBRARIES with generator expressions if that is what is wanted. 2) In the case of static libraries, this prevents a footgun, enforcing that the interface and the implementation are really the same. Otherwise, the LINK_LIBRARIES could contain a generator expression which is evaluated with a different context at build time, and when used as an imported target. That would mean that the result of evaluating the INTERFACE_LINK_LIBRARIES property for a static library would not necessarily be the 'link implementation'. For example: add_library(libone STATIC libone.cpp) add_library(libtwo STATIC libtwo.cpp) add_library(libthree STATIC libthree.cpp) target_link_libraries(libtwo $<$,STATIC_LIBRARY>:libone>) target_link_libraries(libthree libtwo) If the LINK_LIBRARIES content was simply copied to the IMPORTED_LINK_INTERFACE_LIBRARIES, then libthree links to libone, but executables linking to libthree will not link to libone. 3) As the 'implementation is the interface' concept is to be deprecated in the future anyway, this should be fine. --- Source/cmExportFileGenerator.cxx | 44 +++++++++++++++++-- Source/cmTarget.cxx | 50 ++++++++++++++++------ Source/cmTarget.h | 4 +- .../target_link_libraries/CMakeLists.txt | 10 +++++ Tests/CMakeCommands/target_link_libraries/depD.cpp | 13 ++++++ Tests/CMakeCommands/target_link_libraries/depD.h | 11 +++++ .../target_link_libraries/targetB.cpp | 10 +++++ Tests/ExportImport/Export/CMakeLists.txt | 33 +++++++++++++- Tests/ExportImport/Export/testSharedLibDepends.cpp | 8 ++++ Tests/ExportImport/Export/testSharedLibDepends.h | 14 ++++++ .../ExportImport/Export/testSharedLibRequired.cpp | 7 +++ Tests/ExportImport/Export/testSharedLibRequired.h | 12 ++++++ Tests/ExportImport/Import/A/CMakeLists.txt | 11 +++++ Tests/ExportImport/Import/A/deps_shared_iface.cpp | 11 +++++ 14 files changed, 221 insertions(+), 17 deletions(-) create mode 100644 Tests/CMakeCommands/target_link_libraries/depD.cpp create mode 100644 Tests/CMakeCommands/target_link_libraries/depD.h create mode 100644 Tests/CMakeCommands/target_link_libraries/targetB.cpp create mode 100644 Tests/ExportImport/Export/testSharedLibDepends.cpp create mode 100644 Tests/ExportImport/Export/testSharedLibDepends.h create mode 100644 Tests/ExportImport/Export/testSharedLibRequired.cpp create mode 100644 Tests/ExportImport/Export/testSharedLibRequired.h create mode 100644 Tests/ExportImport/Import/A/deps_shared_iface.cpp diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 5e5f455..94e24c7 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -359,9 +359,47 @@ cmExportFileGenerator { return; } - this->SetImportLinkProperty(suffix, target, - "IMPORTED_LINK_INTERFACE_LIBRARIES", - iface->Libraries, properties, missingTargets); + + if (iface->ImplementationIsInterface) + { + this->SetImportLinkProperty(suffix, target, + "IMPORTED_LINK_INTERFACE_LIBRARIES", + iface->Libraries, properties, missingTargets); + return; + } + + const char *propContent; + + if (const char *prop_suffixed = target->GetProperty( + ("LINK_INTERFACE_LIBRARIES" + suffix).c_str())) + { + propContent = prop_suffixed; + } + else if (const char *prop = target->GetProperty( + "LINK_INTERFACE_LIBRARIES")) + { + propContent = prop; + } + else + { + return; + } + + if (!*propContent) + { + properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = ""; + return; + } + + std::string prepro = cmGeneratorExpression::Preprocess(propContent, + preprocessRule); + if (!prepro.empty()) + { + this->ResolveTargetsInGeneratorExpressions(prepro, target, + missingTargets, + ReplaceFreeTargets); + properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = prepro; + } } //---------------------------------------------------------------------------- diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 2cfb1bf..9b50b8e 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -4896,16 +4896,30 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, { std::string linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES"; linkProp += suffix; - if(const char* config_libs = this->GetProperty(linkProp.c_str())) + + const char *propertyLibs = this->GetProperty(linkProp.c_str()); + + if(!propertyLibs) { - cmSystemTools::ExpandListArgument(config_libs, - info.LinkInterface.Libraries); + linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES"; + propertyLibs = this->GetProperty(linkProp.c_str()); } - else if(const char* libs = - this->GetProperty("IMPORTED_LINK_INTERFACE_LIBRARIES")) + if(propertyLibs) { - cmSystemTools::ExpandListArgument(libs, - info.LinkInterface.Libraries); + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + + cmGeneratorExpressionDAGChecker dagChecker(lfbt, + this->GetName(), + linkProp, 0, 0); + cmSystemTools::ExpandListArgument(ge.Parse(propertyLibs) + ->Evaluate(this->Makefile, + desired_config.c_str(), + false, + headTarget, + this, + &dagChecker), + info.LinkInterface.Libraries); } } @@ -5019,18 +5033,20 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, // An explicit list of interface libraries may be set for shared // libraries and executables that export symbols. const char* explicitLibraries = 0; + std::string linkIfaceProp; if(this->GetType() == cmTarget::SHARED_LIBRARY || this->IsExecutableWithExports()) { // Lookup the per-configuration property. - std::string propName = "LINK_INTERFACE_LIBRARIES"; - propName += suffix; - explicitLibraries = this->GetProperty(propName.c_str()); + linkIfaceProp = "LINK_INTERFACE_LIBRARIES"; + linkIfaceProp += suffix; + explicitLibraries = this->GetProperty(linkIfaceProp.c_str()); // If not set, try the generic property. if(!explicitLibraries) { - explicitLibraries = this->GetProperty("LINK_INTERFACE_LIBRARIES"); + linkIfaceProp = "LINK_INTERFACE_LIBRARIES"; + explicitLibraries = this->GetProperty(linkIfaceProp.c_str()); } } @@ -5048,7 +5064,16 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, if(explicitLibraries) { // The interface libraries have been explicitly set. - cmSystemTools::ExpandListArgument(explicitLibraries, iface.Libraries); + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + cmGeneratorExpressionDAGChecker dagChecker(lfbt, this->GetName(), + linkIfaceProp, 0, 0); + cmSystemTools::ExpandListArgument(ge.Parse(explicitLibraries)->Evaluate( + this->Makefile, + config, + false, + headTarget, + this, &dagChecker), iface.Libraries); if(this->GetType() == cmTarget::SHARED_LIBRARY) { @@ -5091,6 +5116,7 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface, // The link implementation is the default link interface. LinkImplementation const* impl = this->GetLinkImplementation(config, headTarget); + iface.ImplementationIsInterface = true; iface.Libraries = impl->Libraries; iface.WrongConfigLibraries = impl->WrongConfigLibraries; if(this->GetType() == cmTarget::STATIC_LIBRARY) diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 1188a6a..b4d053d 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -258,7 +258,9 @@ public: // Needed only for OLD behavior of CMP0003. std::vector WrongConfigLibraries; - LinkInterface(): Multiplicity(0) {} + bool ImplementationIsInterface; + + LinkInterface(): Multiplicity(0), ImplementationIsInterface(false) {} }; /** Get the link interface for the given configuration. Returns 0 diff --git a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt index 746d30c..1551c50 100644 --- a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt +++ b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt @@ -80,3 +80,13 @@ assert_property(targetA LINK_INTERFACE_LIBRARIES "") add_library(depIfaceOnly SHARED EXCLUDE_FROM_ALL depIfaceOnly.cpp) generate_export_header(depIfaceOnly) set_property(TARGET depB APPEND PROPERTY LINK_INTERFACE_LIBRARIES depIfaceOnly) + +add_library(depD SHARED depD.cpp) +generate_export_header(depD) +set_property(TARGET depD APPEND PROPERTY + LINK_INTERFACE_LIBRARIES + $<$,EXECUTABLE>:depA> +) + +add_executable(targetB targetB.cpp) +target_link_libraries(targetB depD) diff --git a/Tests/CMakeCommands/target_link_libraries/depD.cpp b/Tests/CMakeCommands/target_link_libraries/depD.cpp new file mode 100644 index 0000000..b02c76c --- /dev/null +++ b/Tests/CMakeCommands/target_link_libraries/depD.cpp @@ -0,0 +1,13 @@ + +#include "depD.h" + +int DepD::foo() +{ + return 0; +} + +DepA DepD::getA() +{ + DepA a; + return a; +} diff --git a/Tests/CMakeCommands/target_link_libraries/depD.h b/Tests/CMakeCommands/target_link_libraries/depD.h new file mode 100644 index 0000000..d24ff5f --- /dev/null +++ b/Tests/CMakeCommands/target_link_libraries/depD.h @@ -0,0 +1,11 @@ + +#include "depd_export.h" + +#include "depA.h" + +struct DEPD_EXPORT DepD +{ + int foo(); + + DepA getA(); +}; diff --git a/Tests/CMakeCommands/target_link_libraries/targetB.cpp b/Tests/CMakeCommands/target_link_libraries/targetB.cpp new file mode 100644 index 0000000..063d63a --- /dev/null +++ b/Tests/CMakeCommands/target_link_libraries/targetB.cpp @@ -0,0 +1,10 @@ + +#include "depD.h" + +int main(int argc, char **argv) +{ + DepD d; + DepA a = d.getA(); + + return d.foo() + a.foo(); +} diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt index 569845a..779d889 100644 --- a/Tests/ExportImport/Export/CMakeLists.txt +++ b/Tests/ExportImport/Export/CMakeLists.txt @@ -158,6 +158,36 @@ set_property(TARGET testLibRequired APPEND PROPERTY $ ) +include(GenerateExportHeader) + +add_library(testSharedLibRequired SHARED testSharedLibRequired.cpp) +generate_export_header(testSharedLibRequired) +set_property(TARGET testSharedLibRequired APPEND PROPERTY + INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}" +) +set_property(TARGET testSharedLibRequired APPEND PROPERTY + INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}" + "${CMAKE_CURRENT_SOURCE_DIR}" +) + +add_library(testSharedLibDepends SHARED testSharedLibDepends.cpp) +set_property(TARGET testSharedLibDepends APPEND PROPERTY + INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}" +) +generate_export_header(testSharedLibDepends) + +set_property(TARGET testSharedLibDepends APPEND PROPERTY + INTERFACE_INCLUDE_DIRECTORIES + $ +) +set_property(TARGET testSharedLibDepends APPEND PROPERTY + LINK_INTERFACE_LIBRARIES + $<1:$> +) + +# LINK_PRIVATE because the LINK_INTERFACE_LIBRARIES is specified above. +target_link_libraries(testSharedLibDepends LINK_PRIVATE testSharedLibRequired) + install(TARGETS testLibRequired testLibIncludeRequired1 testLibIncludeRequired2 @@ -165,10 +195,11 @@ install(TARGETS testLibRequired testLibIncludeRequired4 testLibIncludeRequired5 testLibIncludeRequired6 + testSharedLibRequired EXPORT RequiredExp DESTINATION lib ) install(EXPORT RequiredExp NAMESPACE Req:: FILE testLibRequiredConfig.cmake DESTINATION lib/cmake/testLibRequired) -install(TARGETS testLibDepends EXPORT DependsExp DESTINATION lib ) +install(TARGETS testLibDepends testSharedLibDepends EXPORT DependsExp DESTINATION lib ) install(EXPORT DependsExp FILE testLibDependsConfig.cmake DESTINATION lib/cmake/testLibDepends) diff --git a/Tests/ExportImport/Export/testSharedLibDepends.cpp b/Tests/ExportImport/Export/testSharedLibDepends.cpp new file mode 100644 index 0000000..e279207 --- /dev/null +++ b/Tests/ExportImport/Export/testSharedLibDepends.cpp @@ -0,0 +1,8 @@ + +#include "testSharedLibDepends.h" + +int TestSharedLibDepends::foo() +{ + TestSharedLibRequired req; + return req.foo(); +} diff --git a/Tests/ExportImport/Export/testSharedLibDepends.h b/Tests/ExportImport/Export/testSharedLibDepends.h new file mode 100644 index 0000000..b93143a --- /dev/null +++ b/Tests/ExportImport/Export/testSharedLibDepends.h @@ -0,0 +1,14 @@ + +#ifndef TESTSHAREDLIBDEPENDS_H +#define TESTSHAREDLIBDEPENDS_H + +#include "testsharedlibdepends_export.h" + +#include "testSharedLibRequired.h" + +struct TESTSHAREDLIBDEPENDS_EXPORT TestSharedLibDepends +{ + int foo(); +}; + +#endif diff --git a/Tests/ExportImport/Export/testSharedLibRequired.cpp b/Tests/ExportImport/Export/testSharedLibRequired.cpp new file mode 100644 index 0000000..1ac34aa --- /dev/null +++ b/Tests/ExportImport/Export/testSharedLibRequired.cpp @@ -0,0 +1,7 @@ + +#include "testSharedLibRequired.h" + +int TestSharedLibRequired::foo() +{ + return 0; +} diff --git a/Tests/ExportImport/Export/testSharedLibRequired.h b/Tests/ExportImport/Export/testSharedLibRequired.h new file mode 100644 index 0000000..edaddd4 --- /dev/null +++ b/Tests/ExportImport/Export/testSharedLibRequired.h @@ -0,0 +1,12 @@ + +#ifndef TESTSHAREDLIBREQUIRED_H +#define TESTSHAREDLIBREQUIRED_H + +#include "testsharedlibrequired_export.h" + +struct TESTSHAREDLIBREQUIRED_EXPORT TestSharedLibRequired +{ + int foo(); +}; + +#endif diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt index 56cfea0..abb2ab0 100644 --- a/Tests/ExportImport/Import/A/CMakeLists.txt +++ b/Tests/ExportImport/Import/A/CMakeLists.txt @@ -167,3 +167,14 @@ set_property(TARGET deps_iface APPEND PROPERTY INCLUDE_DIRECTORIES $ ) + +add_executable(deps_shared_iface deps_shared_iface.cpp) +target_link_libraries(deps_shared_iface testSharedLibDepends) +set_property(TARGET deps_shared_iface APPEND PROPERTY + COMPILE_DEFINITIONS + $ +) +set_property(TARGET deps_shared_iface APPEND PROPERTY + INCLUDE_DIRECTORIES + $ +) diff --git a/Tests/ExportImport/Import/A/deps_shared_iface.cpp b/Tests/ExportImport/Import/A/deps_shared_iface.cpp new file mode 100644 index 0000000..4f7eb23 --- /dev/null +++ b/Tests/ExportImport/Import/A/deps_shared_iface.cpp @@ -0,0 +1,11 @@ + + +#include "testSharedLibDepends.h" + +int main(int,char **) +{ + TestSharedLibDepends dep; + TestSharedLibRequired req; + + return dep.foo() + req.foo(); +} -- cgit v0.12