diff options
author | Brad King <brad.king@kitware.com> | 2024-05-22 13:20:40 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2024-05-22 13:20:51 (GMT) |
commit | c8c1e1a9caf2b3f79a9f40b8997b6161a94e9fc1 (patch) | |
tree | 4917a886629ea748d46e7062f607c99fa3c12386 | |
parent | 78a2bef26b90dda4a3deb0aef5a72a6c9c1590a9 (diff) | |
parent | c16acd35b36245575744e3c31a581c62880481a5 (diff) | |
download | CMake-c8c1e1a9caf2b3f79a9f40b8997b6161a94e9fc1.zip CMake-c8c1e1a9caf2b3f79a9f40b8997b6161a94e9fc1.tar.gz CMake-c8c1e1a9caf2b3f79a9f40b8997b6161a94e9fc1.tar.bz2 |
Merge topic 'custom-transitive-properties'
c16acd35b3 GenEx: Add support for custom transitive link properties
b9ee79b8a1 GenEx: Add support for custom transitive compile properties
633afa0b2e cmGeneratorExpressionDAGChecker: Make config name available in constructor
e64d09a729 cmGeneratorTarget: Add GetLinkImplementationClosure mode for linking
a11cbcc268 cmGeneratorTarget: Add TransitiveProperty constructor to help some compilers
af59289904 Help: Format TARGET_PROPERTY special evaluation rules as a definition list
Acked-by: Kitware Robot <kwrobot@kitware.com>
Tested-by: buildbot <buildbot@kitware.com>
Acked-by: alcroito <alexandru.croitor@qt.io>
Merge-request: !9516
39 files changed, 1020 insertions, 93 deletions
diff --git a/Help/manual/cmake-buildsystem.7.rst b/Help/manual/cmake-buildsystem.7.rst index 93d55c7..eb25a4a 100644 --- a/Help/manual/cmake-buildsystem.7.rst +++ b/Help/manual/cmake-buildsystem.7.rst @@ -602,6 +602,65 @@ linking consumers. List of files on which linking the target's consumers depends, for those that are executables, shared libraries, or module libraries. +.. _`Custom Transitive Properties`: + +Custom Transitive Properties +---------------------------- + +.. versionadded:: 3.30 + +The :genex:`TARGET_PROPERTY` generator expression evaluates the above +`build specification <Target Build Specification_>`_ and +`usage requirement <Target Usage Requirements_>`_ properties +as builtin transitive properties. It also supports custom transitive +properties defined by the :prop_tgt:`TRANSITIVE_COMPILE_PROPERTIES` +and :prop_tgt:`TRANSITIVE_LINK_PROPERTIES` properties on the target +and its link dependencies. + +For example: + +.. code-block:: cmake + + add_library(example INTERFACE) + set_target_properties(example PROPERTIES + TRANSITIVE_COMPILE_PROPERTIES "CUSTOM_C" + TRANSITIVE_LINK_PROPERTIES "CUSTOM_L" + + INTERFACE_CUSTOM_C "EXAMPLE_CUSTOM_C" + INTERFACE_CUSTOM_L "EXAMPLE_CUSTOM_L" + ) + + add_library(mylib STATIC mylib.c) + target_link_libraries(mylib PRIVATE example) + set_target_properties(mylib PROPERTIES + CUSTOM_C "MYLIB_PRIVATE_CUSTOM_C" + CUSTOM_L "MYLIB_PRIVATE_CUSTOM_L" + INTERFACE_CUSTOM_C "MYLIB_IFACE_CUSTOM_C" + INTERFACE_CUSTOM_L "MYLIB_IFACE_CUSTOM_L" + ) + + add_executable(myexe myexe.c) + target_link_libraries(myexe PRIVATE mylib) + set_target_properties(myexe PROPERTIES + CUSTOM_C "MYEXE_CUSTOM_C" + CUSTOM_L "MYEXE_CUSTOM_L" + ) + + add_custom_target(print ALL VERBATIM + COMMAND ${CMAKE_COMMAND} -E echo + # Prints "MYLIB_PRIVATE_CUSTOM_C;EXAMPLE_CUSTOM_C" + "$<TARGET_PROPERTY:mylib,CUSTOM_C>" + + # Prints "MYLIB_PRIVATE_CUSTOM_L;EXAMPLE_CUSTOM_L" + "$<TARGET_PROPERTY:mylib,CUSTOM_L>" + + # Prints "MYEXE_CUSTOM_C" + "$<TARGET_PROPERTY:myexe,CUSTOM_C>" + + # Prints "MYEXE_CUSTOM_L;MYLIB_IFACE_CUSTOM_L;EXAMPLE_CUSTOM_L" + "$<TARGET_PROPERTY:myexe,CUSTOM_L>" + ) + .. _`Compatible Interface Properties`: Compatible Interface Properties diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index 49d94ef..bc32452 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -1775,11 +1775,11 @@ These expressions look up the values of The expressions have special evaluation rules for some properties: -* :ref:`Target Build Specification` properties evaluate as a - :ref:`semicolon-separated list <CMake Language Lists>` representing the union - of the value on the target itself with the values of the corresponding - :ref:`Target Usage Requirements` on targets named by the target's - :prop_tgt:`LINK_LIBRARIES`: +:ref:`Target Build Specification Properties <Target Build Specification>` + These evaluate as a :ref:`semicolon-separated list <CMake Language Lists>` + representing the union of the value on the target itself with the values + of the corresponding :ref:`Target Usage Requirements` on targets named by + the target's :prop_tgt:`LINK_LIBRARIES`: * For :ref:`Target Compile Properties`, evaluation of corresponding usage requirements is transitive over the closure of the linked targets' @@ -1793,10 +1793,11 @@ The expressions have special evaluation rules for some properties: Evaluation of :prop_tgt:`LINK_LIBRARIES` itself is not transitive. -* :ref:`Target Usage Requirements` evaluate as a - :ref:`semicolon-separated list <CMake Language Lists>` representing the union - of the value on the target itself with the values of the same properties on - targets named by the target's :prop_tgt:`INTERFACE_LINK_LIBRARIES`: +:ref:`Target Usage Requirement Properties <Target Usage Requirements>` + These evaluate as a :ref:`semicolon-separated list <CMake Language Lists>` + representing the union of the value on the target itself with the values + of the same properties on targets named by the target's + :prop_tgt:`INTERFACE_LINK_LIBRARIES`: * For :ref:`Transitive Compile Properties`, evaluation is transitive over the closure of the target's :prop_tgt:`INTERFACE_LINK_LIBRARIES` @@ -1809,13 +1810,70 @@ The expressions have special evaluation rules for some properties: Evaluation of :prop_tgt:`INTERFACE_LINK_LIBRARIES` itself is not transitive. -* :ref:`Compatible Interface Properties` evaluate as a single value - combined from the target itself, from targets named by the target's - :prop_tgt:`LINK_LIBRARIES`, and from the transitive closure of the - linked targets' :prop_tgt:`INTERFACE_LINK_LIBRARIES`. Values of a - compatible interface property from multiple targets combine based on - the type of compatibility required by the ``COMPATIBLE_INTERFACE_*`` - property defining it. +:ref:`Custom Transitive Properties` + .. versionadded:: 3.30 + + These are processed during evaluation as follows: + + * Evaluation of :genex:`$<TARGET_PROPERTY:tgt,PROP>` for some property + ``PROP``, named without an ``INTERFACE_`` prefix, + checks the :prop_tgt:`TRANSITIVE_COMPILE_PROPERTIES` + and :prop_tgt:`TRANSITIVE_LINK_PROPERTIES` properties on target ``tgt``, + on targets named by its :prop_tgt:`LINK_LIBRARIES`, and on the + transitive closure of targets named by the linked targets' + :prop_tgt:`INTERFACE_LINK_LIBRARIES`. + + If ``PROP`` is listed by one of those properties, then it evaluates as + a :ref:`semicolon-separated list <CMake Language Lists>` representing + the union of the value on the target itself with the values of the + corresponding ``INTERFACE_PROP`` on targets named by the target's + :prop_tgt:`LINK_LIBRARIES`: + + * If ``PROP`` is named by :prop_tgt:`TRANSITIVE_COMPILE_PROPERTIES`, + evaluation of the corresponding ``INTERFACE_PROP`` is transitive over + the closure of the linked targets' :prop_tgt:`INTERFACE_LINK_LIBRARIES`, + excluding entries guarded by the :genex:`LINK_ONLY` generator expression. + + * If ``PROP`` is named by :prop_tgt:`TRANSITIVE_LINK_PROPERTIES`, + evaluation of the corresponding ``INTERFACE_PROP`` is transitive over + the closure of the linked targets' :prop_tgt:`INTERFACE_LINK_LIBRARIES`, + including entries guarded by the :genex:`LINK_ONLY` generator expression. + + * Evaluation of :genex:`$<TARGET_PROPERTY:tgt,INTERFACE_PROP>` for some + property ``INTERFACE_PROP``, named with an ``INTERFACE_`` prefix, + checks the :prop_tgt:`TRANSITIVE_COMPILE_PROPERTIES` + and :prop_tgt:`TRANSITIVE_LINK_PROPERTIES` properties on target ``tgt``, + and on the transitive closure of targets named by its + :prop_tgt:`INTERFACE_LINK_LIBRARIES`. + + If the corresponding ``PROP`` is listed by one of those properties, + then ``INTERFACE_PROP`` evaluates as a + :ref:`semicolon-separated list <CMake Language Lists>` representing the + union of the value on the target itself with the value of the same + property on targets named by the target's + :prop_tgt:`INTERFACE_LINK_LIBRARIES`: + + * If ``PROP`` is named by :prop_tgt:`TRANSITIVE_COMPILE_PROPERTIES`, + evaluation of the corresponding ``INTERFACE_PROP`` is transitive over + the closure of the target's :prop_tgt:`INTERFACE_LINK_LIBRARIES`, + excluding entries guarded by the :genex:`LINK_ONLY` generator expression. + + * If ``PROP`` is named by :prop_tgt:`TRANSITIVE_LINK_PROPERTIES`, + evaluation of the corresponding ``INTERFACE_PROP`` is transitive over + the closure of the target's :prop_tgt:`INTERFACE_LINK_LIBRARIES`, + including entries guarded by the :genex:`LINK_ONLY` generator expression. + + If a ``PROP`` is named by both :prop_tgt:`TRANSITIVE_COMPILE_PROPERTIES` + and :prop_tgt:`TRANSITIVE_LINK_PROPERTIES`, the latter takes precedence. + +:ref:`Compatible Interface Properties` + These evaluate as a single value combined from the target itself, + from targets named by the target's :prop_tgt:`LINK_LIBRARIES`, and + from the transitive closure of the linked targets' + :prop_tgt:`INTERFACE_LINK_LIBRARIES`. Values of a compatible + interface property from multiple targets combine based on the type + of compatibility required by the ``COMPATIBLE_INTERFACE_*`` property + defining it. Target Artifacts diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 7e640df..549ec53 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -401,6 +401,8 @@ Properties on Targets /prop_tgt/Swift_MODULE_NAME /prop_tgt/SYSTEM /prop_tgt/TEST_LAUNCHER + /prop_tgt/TRANSITIVE_COMPILE_PROPERTIES + /prop_tgt/TRANSITIVE_LINK_PROPERTIES /prop_tgt/TYPE /prop_tgt/UNITY_BUILD /prop_tgt/UNITY_BUILD_BATCH_SIZE diff --git a/Help/prop_tgt/TRANSITIVE_COMPILE_PROPERTIES.rst b/Help/prop_tgt/TRANSITIVE_COMPILE_PROPERTIES.rst new file mode 100644 index 0000000..b190f3b --- /dev/null +++ b/Help/prop_tgt/TRANSITIVE_COMPILE_PROPERTIES.rst @@ -0,0 +1,19 @@ +TRANSITIVE_COMPILE_PROPERTIES +----------------------------- + +.. versionadded:: 3.30 + +Properties that the :genex:`TARGET_PROPERTY` generator expression, on the +target and its dependents, evaluates as the union of values collected from +the transitive closure of link dependencies, excluding entries guarded by +:genex:`LINK_ONLY`. + +The value is a :ref:`semicolon-separated list <CMake Language Lists>` +of :ref:`custom transitive property <Custom Transitive Properties>` names. +Any leading ``INTERFACE_`` prefix is ignored, e.g., ``INTERFACE_PROP`` is +treated as just ``PROP``. + +See documentation of the :genex:`TARGET_PROPERTY` generator expression +for details of custom transitive property evaluation. See also the +:prop_tgt:`TRANSITIVE_LINK_PROPERTIES` target property, which includes +entries guarded by :genex:`LINK_ONLY`. diff --git a/Help/prop_tgt/TRANSITIVE_LINK_PROPERTIES.rst b/Help/prop_tgt/TRANSITIVE_LINK_PROPERTIES.rst new file mode 100644 index 0000000..adb5808 --- /dev/null +++ b/Help/prop_tgt/TRANSITIVE_LINK_PROPERTIES.rst @@ -0,0 +1,19 @@ +TRANSITIVE_LINK_PROPERTIES +-------------------------- + +.. versionadded:: 3.30 + +Properties that the :genex:`TARGET_PROPERTY` generator expression, on the +target and its dependents, evaluates as the union of values collected from +the transitive closure of link dependencies, including entries guarded by +:genex:`LINK_ONLY`. + +The value is a :ref:`semicolon-separated list <CMake Language Lists>` +of :ref:`custom transitive property <Custom Transitive Properties>` names. +Any leading ``INTERFACE_`` prefix is ignored, e.g., ``INTERFACE_PROP`` is +treated as just ``PROP``. + +See documentation of the :genex:`TARGET_PROPERTY` generator expression +for details of custom transitive property evaluation. See also the +:prop_tgt:`TRANSITIVE_COMPILE_PROPERTIES` target property, which excludes +entries guarded by :genex:`LINK_ONLY`.. diff --git a/Help/release/dev/custom-transitive-properties.rst b/Help/release/dev/custom-transitive-properties.rst new file mode 100644 index 0000000..95c6e14 --- /dev/null +++ b/Help/release/dev/custom-transitive-properties.rst @@ -0,0 +1,7 @@ +custom-transitive-properties +---------------------------- + +* The :genex:`TARGET_PROPERTY` generator expression learned to evaluate + :ref:`custom transitive properties <Custom Transitive Properties>` + defined by new :prop_tgt:`TRANSITIVE_COMPILE_PROPERTIES` and + :prop_tgt:`TRANSITIVE_LINK_PROPERTIES` target properties. diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index fbf39e2..9f25904 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -500,9 +500,9 @@ std::string cmCommonTargetGenerator::GetLinkerLauncher( std::string propName = lang + "_LINKER_LAUNCHER"; cmValue launcherProp = this->GeneratorTarget->GetProperty(propName); if (cmNonempty(launcherProp)) { - cmGeneratorExpressionDAGChecker dagChecker(this->GeneratorTarget, propName, - nullptr, nullptr, - this->LocalCommonGenerator); + cmGeneratorExpressionDAGChecker dagChecker( + this->GeneratorTarget, propName, nullptr, nullptr, + this->LocalCommonGenerator, config); std::string evaluatedLinklauncher = cmGeneratorExpression::Evaluate( *launcherProp, this->LocalCommonGenerator, config, this->GeneratorTarget, &dagChecker, this->GeneratorTarget, lang); diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index db0d71a..cc323f4 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -581,7 +581,8 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target, "LINK_LIBRARY_OVERRIDE", nullptr, nullptr, - this->Target->GetLocalGenerator() + this->Target->GetLocalGenerator(), + config }; auto overrideFeature = cmGeneratorExpression::Evaluate( *feature, this->Target->GetLocalGenerator(), config, @@ -599,7 +600,8 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target, "LINK_LIBRARY_OVERRIDE", nullptr, nullptr, - target->GetLocalGenerator() }; + target->GetLocalGenerator(), + config }; auto overrideValue = cmGeneratorExpression::Evaluate( *linkLibraryOverride, target->GetLocalGenerator(), config, target, &dag, target, linkLanguage); diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 2345d64..d877d76 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -152,6 +152,8 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) gte, cmGeneratorExpression::BuildInterface, properties); } this->PopulateCompatibleInterfaceProperties(gte, properties); + this->PopulateCustomTransitiveInterfaceProperties( + gte, cmGeneratorExpression::BuildInterface, properties); this->GenerateInterfaceProperties(gte, os, properties); diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 9bd7f49..a5348f2 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -604,6 +604,27 @@ void cmExportFileGenerator::PopulateCompatibleInterfaceProperties( } } +void cmExportFileGenerator::PopulateCustomTransitiveInterfaceProperties( + cmGeneratorTarget const* target, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties) +{ + this->PopulateInterfaceProperty("TRANSITIVE_COMPILE_PROPERTIES", target, + properties); + this->PopulateInterfaceProperty("TRANSITIVE_LINK_PROPERTIES", target, + properties); + std::set<std::string> ifaceProperties; + for (std::string const& config : this->Configurations) { + for (auto const& i : target->GetCustomTransitiveProperties( + config, cmGeneratorTarget::PropertyFor::Interface)) { + ifaceProperties.emplace(i.second.InterfaceName); + } + } + for (std::string const& ip : ifaceProperties) { + this->PopulateInterfaceProperty(ip, target, preprocessRule, properties); + } +} + void cmExportFileGenerator::GenerateInterfaceProperties( const cmGeneratorTarget* target, std::ostream& os, const ImportPropertyMap& properties) diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index f619576..f275a12 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -145,6 +145,10 @@ protected: ImportPropertyMap& properties); void PopulateCompatibleInterfaceProperties(cmGeneratorTarget const* target, ImportPropertyMap& properties); + void PopulateCustomTransitiveInterfaceProperties( + cmGeneratorTarget const* target, + cmGeneratorExpression::PreprocessContext preprocessRule, + ImportPropertyMap& properties); virtual void GenerateInterfaceProperties( cmGeneratorTarget const* target, std::ostream& os, const ImportPropertyMap& properties); diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 5c95ecd..f5f22ef 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -160,6 +160,8 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) properties); this->PopulateCompatibleInterfaceProperties(gt, properties); + this->PopulateCustomTransitiveInterfaceProperties( + gt, cmGeneratorExpression::InstallInterface, properties); this->GenerateInterfaceProperties(gt, os, properties); diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx index 4c41ff5..7ce5cd9 100644 --- a/Source/cmExportTryCompileFileGenerator.cxx +++ b/Source/cmExportTryCompileFileGenerator.cxx @@ -76,10 +76,12 @@ std::string cmExportTryCompileFileGenerator::FindTargets( // To please constraint checks of DAGChecker, this property must have // LINK_OPTIONS property as parent parentDagChecker = cm::make_unique<cmGeneratorExpressionDAGChecker>( - tgt, "LINK_OPTIONS", nullptr, nullptr, tgt->GetLocalGenerator()); + tgt, "LINK_OPTIONS", nullptr, nullptr, tgt->GetLocalGenerator(), + this->Config); } cmGeneratorExpressionDAGChecker dagChecker( - tgt, propName, nullptr, parentDagChecker.get(), tgt->GetLocalGenerator()); + tgt, propName, nullptr, parentDagChecker.get(), tgt->GetLocalGenerator(), + this->Config); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*prop); diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 0583fd5..8e590fa 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -425,7 +425,7 @@ const std::string& cmGeneratorExpressionInterpreter::Evaluate( cmGeneratorExpressionDAGChecker dagChecker( this->HeadTarget, property == "COMPILE_FLAGS" ? "COMPILE_OPTIONS" : property, nullptr, - nullptr, this->LocalGenerator); + nullptr, this->LocalGenerator, this->Config); return this->CompiledGeneratorExpression->Evaluate( this->LocalGenerator, this->Config, this->HeadTarget, &dagChecker, nullptr, diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index bb1f4b4..aad25f0 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -20,17 +20,19 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker( cmGeneratorTarget const* target, std::string property, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* parent, cmLocalGenerator const* contextLG) + cmGeneratorExpressionDAGChecker* parent, cmLocalGenerator const* contextLG, + std::string const& contextConfig) : cmGeneratorExpressionDAGChecker(cmListFileBacktrace(), target, std::move(property), content, parent, - contextLG) + contextLG, contextConfig) { } cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker( cmListFileBacktrace backtrace, cmGeneratorTarget const* target, std::string property, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* parent, cmLocalGenerator const* contextLG) + cmGeneratorExpressionDAGChecker* parent, cmLocalGenerator const* contextLG, + std::string const& contextConfig) : Parent(parent) , Top(parent ? parent->Top : this) , Target(target) @@ -42,7 +44,9 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker( this->TopIsTransitiveProperty = parent->TopIsTransitiveProperty; } else { this->TopIsTransitiveProperty = - this->Target->IsTransitiveProperty(this->Property, contextLG) + this->Target + ->IsTransitiveProperty(this->Property, contextLG, contextConfig, + this->EvaluatingLinkLibraries()) .has_value(); } diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index b230188..8b0eea7 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -22,12 +22,14 @@ struct cmGeneratorExpressionDAGChecker std::string property, const GeneratorExpressionContent* content, cmGeneratorExpressionDAGChecker* parent, - cmLocalGenerator const* contextLG); + cmLocalGenerator const* contextLG, + std::string const& contextConfig); cmGeneratorExpressionDAGChecker(cmGeneratorTarget const* target, std::string property, const GeneratorExpressionContent* content, cmGeneratorExpressionDAGChecker* parent, - cmLocalGenerator const* contextLG); + cmLocalGenerator const* contextLG, + std::string const& contextConfig); enum Result { diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 5945e41..01cd18d 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -488,7 +488,7 @@ protected: cmGeneratorExpressionDAGChecker dagChecker( context->Backtrace, context->HeadTarget, genexOperator + ":" + expression, content, dagCheckerParent, - context->LG); + context->LG, context->Config); switch (dagChecker.Check()) { case cmGeneratorExpressionDAGChecker::SELF_REFERENCE: case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: { @@ -2873,19 +2873,22 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode return target->GetLinkerLanguage(context->Config); } + bool const evaluatingLinkLibraries = + dagCheckerParent && dagCheckerParent->EvaluatingLinkLibraries(); + std::string interfacePropertyName; bool isInterfaceProperty = false; cmGeneratorTarget::UseTo usage = cmGeneratorTarget::UseTo::Compile; if (cm::optional<cmGeneratorTarget::TransitiveProperty> transitiveProp = - target->IsTransitiveProperty(propertyName, context->LG)) { + target->IsTransitiveProperty(propertyName, context->LG, + context->Config, + evaluatingLinkLibraries)) { interfacePropertyName = std::string(transitiveProp->InterfaceName); isInterfaceProperty = transitiveProp->InterfaceName == propertyName; usage = transitiveProp->Usage; } - bool evaluatingLinkLibraries = false; - if (dagCheckerParent) { // This $<TARGET_PROPERTY:...> node has been reached while evaluating // another target property value. Check that the outermost evaluation @@ -2894,8 +2897,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode dagCheckerParent->EvaluatingPICExpression() || dagCheckerParent->EvaluatingLinkerLauncher()) { // No check required. - } else if (dagCheckerParent->EvaluatingLinkLibraries()) { - evaluatingLinkLibraries = true; + } else if (evaluatingLinkLibraries) { if (!interfacePropertyName.empty()) { reportError( context, content->GetOriginalExpression(), @@ -2915,9 +2917,9 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode dagCheckerParent, usage)); } - cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, target, - propertyName, content, - dagCheckerParent, context->LG); + cmGeneratorExpressionDAGChecker dagChecker( + context->Backtrace, target, propertyName, content, dagCheckerParent, + context->LG, context->Config); switch (dagChecker.Check()) { case cmGeneratorExpressionDAGChecker::SELF_REFERENCE: diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index ce53316..aa3e36f 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -511,11 +511,15 @@ void cmGeneratorTarget::ClearSourcesCache() this->SourcesAreContextDependent = Tribool::Indeterminate; this->Objects.clear(); this->VisitedConfigsForObjects.clear(); + this->LinkImplClosureForLinkMap.clear(); + this->LinkImplClosureForUsageMap.clear(); this->LinkImplMap.clear(); this->LinkImplUsageRequirementsOnlyMap.clear(); this->IncludeDirectoriesCache.clear(); this->CompileOptionsCache.clear(); this->CompileDefinitionsCache.clear(); + this->CustomTransitiveBuildPropertiesMap.clear(); + this->CustomTransitiveInterfacePropertiesMap.clear(); this->PrecompileHeadersCache.clear(); this->LinkOptionsCache.clear(); this->LinkDirectoriesCache.clear(); @@ -707,8 +711,8 @@ std::string cmGeneratorTarget::GetLinkerTypeProperty( std::string propName{ "LINKER_TYPE" }; auto linkerType = this->GetProperty(propName); if (!linkerType.IsEmpty()) { - cmGeneratorExpressionDAGChecker dagChecker(this, propName, nullptr, - nullptr, this->LocalGenerator); + cmGeneratorExpressionDAGChecker dagChecker( + this, propName, nullptr, nullptr, this->LocalGenerator, config); auto ltype = cmGeneratorExpression::Evaluate(*linkerType, this->GetLocalGenerator(), config, this, &dagChecker, this, lang); @@ -1174,7 +1178,7 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory( if (iter == this->SystemIncludesCache.end()) { cmGeneratorExpressionDAGChecker dagChecker( this, "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr, - this->LocalGenerator); + this->LocalGenerator, config); bool excludeImported = this->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED"); @@ -1186,7 +1190,7 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory( } std::vector<cmGeneratorTarget const*> const& deps = - this->GetLinkImplementationClosure(config); + this->GetLinkImplementationClosure(config, UseTo::Compile); for (cmGeneratorTarget const* dep : deps) { handleSystemIncludesDep(this->LocalGenerator, dep, config, this, &dagChecker, result, excludeImported, language); @@ -1934,8 +1938,8 @@ void cmGeneratorTarget::GetAutoUicOptions(std::vector<std::string>& result, return; } - cmGeneratorExpressionDAGChecker dagChecker(this, "AUTOUIC_OPTIONS", nullptr, - nullptr, this->LocalGenerator); + cmGeneratorExpressionDAGChecker dagChecker( + this, "AUTOUIC_OPTIONS", nullptr, nullptr, this->LocalGenerator, config); cmExpandList(cmGeneratorExpression::Evaluate(prop, this->LocalGenerator, config, this, &dagChecker), result); diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 51f112e..8f27a91 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -892,6 +892,13 @@ public: struct TransitiveProperty { +#if defined(__SUNPRO_CC) || (defined(__ibmxl__) && defined(__clang__)) + TransitiveProperty(cm::string_view interfaceName, UseTo usage) + : InterfaceName(interfaceName) + , Usage(usage) + { + } +#endif cm::string_view InterfaceName; UseTo Usage; }; @@ -900,7 +907,8 @@ public: BuiltinTransitiveProperties; cm::optional<TransitiveProperty> IsTransitiveProperty( - cm::string_view prop, cmLocalGenerator const* lg) const; + cm::string_view prop, cmLocalGenerator const* lg, + std::string const& config, bool evaluatingLinkLibraries) const; bool HaveInstallTreeRPATH(const std::string& config) const; @@ -982,6 +990,30 @@ public: bool DiscoverSyntheticTargets(cmSyntheticTargetCache& cache, std::string const& config); + class CustomTransitiveProperty : public TransitiveProperty + { + std::unique_ptr<std::string> InterfaceNameBuf; + CustomTransitiveProperty(std::unique_ptr<std::string> interfaceNameBuf, + UseTo usage); + + public: + CustomTransitiveProperty(std::string interfaceName, UseTo usage); + }; + struct CustomTransitiveProperties + : public std::map<std::string, CustomTransitiveProperty> + { + void Add(cmValue props, UseTo usage); + }; + + enum class PropertyFor + { + Build, + Interface, + }; + + CustomTransitiveProperties const& GetCustomTransitiveProperties( + std::string const& config, PropertyFor propertyFor) const; + private: void AddSourceCommon(const std::string& src, bool before = false); @@ -1049,6 +1081,11 @@ private: std::string const& base, std::string const& suffix, std::string const& name, cmValue version) const; + mutable std::map<std::string, CustomTransitiveProperties> + CustomTransitiveBuildPropertiesMap; + mutable std::map<std::string, CustomTransitiveProperties> + CustomTransitiveInterfacePropertiesMap; + struct CompatibleInterfacesBase { std::set<std::string> PropsBool; @@ -1080,7 +1117,8 @@ private: { bool Done = false; }; - mutable std::map<std::string, LinkImplClosure> LinkImplClosureMap; + mutable std::map<std::string, LinkImplClosure> LinkImplClosureForLinkMap; + mutable std::map<std::string, LinkImplClosure> LinkImplClosureForUsageMap; using LinkInterfaceMapType = std::map<std::string, cmHeadToLinkInterfaceMap>; mutable LinkInterfaceMapType LinkInterfaceMap; @@ -1298,9 +1336,15 @@ private: void ComputeLinkInterfaceRuntimeLibraries( const std::string& config, cmOptionalLinkInterface& iface) const; + // If this method is made public, or call sites are added outside of + // methods computing cached members, add dedicated caching members. + std::vector<cmGeneratorTarget const*> GetLinkInterfaceClosure( + std::string const& config, cmGeneratorTarget const* headTarget, + UseTo usage) const; + public: const std::vector<const cmGeneratorTarget*>& GetLinkImplementationClosure( - const std::string& config) const; + const std::string& config, UseTo usage) const; mutable std::map<std::string, std::string> MaxLanguageStandards; std::map<std::string, std::string> const& GetMaxLanguageStandards() const diff --git a/Source/cmGeneratorTarget_CompatibleInterface.cxx b/Source/cmGeneratorTarget_CompatibleInterface.cxx index b6eb373..3af205e 100644 --- a/Source/cmGeneratorTarget_CompatibleInterface.cxx +++ b/Source/cmGeneratorTarget_CompatibleInterface.cxx @@ -31,6 +31,10 @@ #include "cmSystemTools.h" #include "cmValue.h" +namespace { +using UseTo = cmGeneratorTarget::UseTo; +} + const cmGeneratorTarget::CompatibleInterfacesBase& cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const { @@ -41,7 +45,7 @@ cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const compat.PropsBool.insert("POSITION_INDEPENDENT_CODE"); compat.PropsString.insert("AUTOUIC_OPTIONS"); std::vector<cmGeneratorTarget const*> const& deps = - this->GetLinkImplementationClosure(config); + this->GetLinkImplementationClosure(config, UseTo::Compile); for (cmGeneratorTarget const* li : deps) { #define CM_READ_COMPATIBLE_INTERFACE(X, x) \ if (cmValue prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) { \ @@ -573,7 +577,7 @@ PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt, assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet)); std::vector<cmGeneratorTarget const*> const& deps = - tgt->GetLinkImplementationClosure(config); + tgt->GetLinkImplementationClosure(config, UseTo::Compile); if (deps.empty()) { return propContent; diff --git a/Source/cmGeneratorTarget_IncludeDirectories.cxx b/Source/cmGeneratorTarget_IncludeDirectories.cxx index eaa3959..2b45e1c 100644 --- a/Source/cmGeneratorTarget_IncludeDirectories.cxx +++ b/Source/cmGeneratorTarget_IncludeDirectories.cxx @@ -48,8 +48,8 @@ std::string AddLangSpecificInterfaceIncludeDirectories( cmGeneratorExpressionDAGChecker* context) { cmGeneratorExpressionDAGChecker dag{ - target->GetBacktrace(), target, propertyName, nullptr, context, - target->GetLocalGenerator() + target->GetBacktrace(), target, propertyName, nullptr, context, + target->GetLocalGenerator(), config }; switch (dag.Check()) { case cmGeneratorExpressionDAGChecker::SELF_REFERENCE: @@ -101,8 +101,8 @@ void AddLangSpecificImplicitIncludeDirectories( if (const auto* libraries = target->GetLinkImplementationLibraries(config, UseTo::Compile)) { cmGeneratorExpressionDAGChecker dag{ - target->GetBacktrace(), target, propertyName, nullptr, nullptr, - target->GetLocalGenerator() + target->GetBacktrace(), target, propertyName, nullptr, nullptr, + target->GetLocalGenerator(), config }; for (const cmLinkImplItem& library : libraries->Libraries) { @@ -254,8 +254,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( std::vector<BT<std::string>> includes; std::unordered_set<std::string> uniqueIncludes; - cmGeneratorExpressionDAGChecker dagChecker( - this, "INCLUDE_DIRECTORIES", nullptr, nullptr, this->LocalGenerator); + cmGeneratorExpressionDAGChecker dagChecker(this, "INCLUDE_DIRECTORIES", + nullptr, nullptr, + this->LocalGenerator, config); cmList debugProperties{ this->Makefile->GetDefinition( "CMAKE_DEBUG_TARGET_PROPERTIES") }; diff --git a/Source/cmGeneratorTarget_Link.cxx b/Source/cmGeneratorTarget_Link.cxx index 3ab36b6..0799429 100644 --- a/Source/cmGeneratorTarget_Link.cxx +++ b/Source/cmGeneratorTarget_Link.cxx @@ -268,23 +268,40 @@ static void processILibs(const std::string& config, cmGeneratorTarget const* headTarget, cmLinkItem const& item, cmGlobalGenerator* gg, std::vector<cmGeneratorTarget const*>& tgts, - std::set<cmGeneratorTarget const*>& emitted) + std::set<cmGeneratorTarget const*>& emitted, + UseTo usage) { if (item.Target && emitted.insert(item.Target).second) { tgts.push_back(item.Target); if (cmLinkInterfaceLibraries const* iface = - item.Target->GetLinkInterfaceLibraries(config, headTarget, - UseTo::Compile)) { + item.Target->GetLinkInterfaceLibraries(config, headTarget, usage)) { for (cmLinkItem const& lib : iface->Libraries) { - processILibs(config, headTarget, lib, gg, tgts, emitted); + processILibs(config, headTarget, lib, gg, tgts, emitted, usage); } } } } +std::vector<cmGeneratorTarget const*> +cmGeneratorTarget::GetLinkInterfaceClosure(std::string const& config, + cmGeneratorTarget const* headTarget, + UseTo usage) const +{ + cmGlobalGenerator* gg = this->GetLocalGenerator()->GetGlobalGenerator(); + std::vector<cmGeneratorTarget const*> tgts; + std::set<cmGeneratorTarget const*> emitted; + if (cmLinkInterfaceLibraries const* iface = + this->GetLinkInterfaceLibraries(config, headTarget, usage)) { + for (cmLinkItem const& lib : iface->Libraries) { + processILibs(config, headTarget, lib, gg, tgts, emitted, usage); + } + } + return tgts; +} + const std::vector<const cmGeneratorTarget*>& -cmGeneratorTarget::GetLinkImplementationClosure( - const std::string& config) const +cmGeneratorTarget::GetLinkImplementationClosure(const std::string& config, + UseTo usage) const { // There is no link implementation for targets that cannot compile sources. if (!this->CanCompileSources()) { @@ -292,18 +309,21 @@ cmGeneratorTarget::GetLinkImplementationClosure( return empty; } - LinkImplClosure& tgts = this->LinkImplClosureMap[config]; + LinkImplClosure& tgts = + (usage == UseTo::Compile ? this->LinkImplClosureForUsageMap[config] + : this->LinkImplClosureForLinkMap[config]); if (!tgts.Done) { tgts.Done = true; std::set<cmGeneratorTarget const*> emitted; cmLinkImplementationLibraries const* impl = - this->GetLinkImplementationLibraries(config, UseTo::Compile); + this->GetLinkImplementationLibraries(config, usage); assert(impl); for (cmLinkImplItem const& lib : impl->Libraries) { processILibs(config, this, lib, - this->LocalGenerator->GetGlobalGenerator(), tgts, emitted); + this->LocalGenerator->GetGlobalGenerator(), tgts, emitted, + usage); } } return tgts; @@ -518,7 +538,7 @@ void cmGeneratorTarget::ExpandLinkItems(std::string const& prop, } // Keep this logic in sync with ComputeLinkImplementationLibraries. cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr, - this->LocalGenerator); + this->LocalGenerator, config); // The $<LINK_ONLY> expression may be in a link interface to specify // private link dependencies that are otherwise excluded from usage // requirements. @@ -1268,8 +1288,8 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( // Collect libraries directly linked in this configuration. for (auto const& entry : entryRange) { // Keep this logic in sync with ExpandLinkItems. - cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_LIBRARIES", nullptr, - nullptr, this->LocalGenerator); + cmGeneratorExpressionDAGChecker dagChecker( + this, "LINK_LIBRARIES", nullptr, nullptr, this->LocalGenerator, config); // The $<LINK_ONLY> expression may be used to specify link dependencies // that are otherwise excluded from usage requirements. if (usage == UseTo::Compile) { diff --git a/Source/cmGeneratorTarget_LinkDirectories.cxx b/Source/cmGeneratorTarget_LinkDirectories.cxx index 0955dfb..bd89497 100644 --- a/Source/cmGeneratorTarget_LinkDirectories.cxx +++ b/Source/cmGeneratorTarget_LinkDirectories.cxx @@ -125,8 +125,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories( std::vector<BT<std::string>> result; std::unordered_set<std::string> uniqueDirectories; - cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DIRECTORIES", nullptr, - nullptr, this->LocalGenerator); + cmGeneratorExpressionDAGChecker dagChecker( + this, "LINK_DIRECTORIES", nullptr, nullptr, this->LocalGenerator, config); cmList debugProperties{ this->Makefile->GetDefinition( "CMAKE_DEBUG_TARGET_PROPERTIES") }; diff --git a/Source/cmGeneratorTarget_Options.cxx b/Source/cmGeneratorTarget_Options.cxx index 05f325d..f77ef72 100644 --- a/Source/cmGeneratorTarget_Options.cxx +++ b/Source/cmGeneratorTarget_Options.cxx @@ -217,8 +217,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions( std::vector<BT<std::string>> result; std::unordered_set<std::string> uniqueOptions; - cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_OPTIONS", nullptr, - nullptr, this->LocalGenerator); + cmGeneratorExpressionDAGChecker dagChecker( + this, "COMPILE_OPTIONS", nullptr, nullptr, this->LocalGenerator, config); cmList debugProperties{ this->Makefile->GetDefinition( "CMAKE_DEBUG_TARGET_PROPERTIES") }; @@ -258,8 +258,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileFeatures( std::vector<BT<std::string>> result; std::unordered_set<std::string> uniqueFeatures; - cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_FEATURES", nullptr, - nullptr, this->LocalGenerator); + cmGeneratorExpressionDAGChecker dagChecker( + this, "COMPILE_FEATURES", nullptr, nullptr, this->LocalGenerator, config); cmList debugProperties{ this->Makefile->GetDefinition( "CMAKE_DEBUG_TARGET_PROPERTIES") }; @@ -308,8 +308,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( std::vector<BT<std::string>> list; std::unordered_set<std::string> uniqueOptions; - cmGeneratorExpressionDAGChecker dagChecker( - this, "COMPILE_DEFINITIONS", nullptr, nullptr, this->LocalGenerator); + cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_DEFINITIONS", + nullptr, nullptr, + this->LocalGenerator, config); cmList debugProperties{ this->Makefile->GetDefinition( "CMAKE_DEBUG_TARGET_PROPERTIES") }; @@ -372,8 +373,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders( } std::unordered_set<std::string> uniqueOptions; - cmGeneratorExpressionDAGChecker dagChecker( - this, "PRECOMPILE_HEADERS", nullptr, nullptr, this->LocalGenerator); + cmGeneratorExpressionDAGChecker dagChecker(this, "PRECOMPILE_HEADERS", + nullptr, nullptr, + this->LocalGenerator, config); cmList debugProperties{ this->Makefile->GetDefinition( "CMAKE_DEBUG_TARGET_PROPERTIES") }; @@ -430,8 +432,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( std::vector<BT<std::string>> result; std::unordered_set<std::string> uniqueOptions; - cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_OPTIONS", nullptr, - nullptr, this->LocalGenerator); + cmGeneratorExpressionDAGChecker dagChecker( + this, "LINK_OPTIONS", nullptr, nullptr, this->LocalGenerator, config); cmList debugProperties{ this->Makefile->GetDefinition( "CMAKE_DEBUG_TARGET_PROPERTIES") }; @@ -599,8 +601,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions( std::vector<BT<std::string>> result; std::unordered_set<std::string> uniqueOptions; - cmGeneratorExpressionDAGChecker dagChecker( - this, "STATIC_LIBRARY_OPTIONS", nullptr, nullptr, this->LocalGenerator); + cmGeneratorExpressionDAGChecker dagChecker(this, "STATIC_LIBRARY_OPTIONS", + nullptr, nullptr, + this->LocalGenerator, config); EvaluatedTargetPropertyEntries entries; if (cmValue linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) { @@ -631,8 +634,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends( { std::vector<BT<std::string>> result; std::unordered_set<std::string> uniqueOptions; - cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DEPENDS", nullptr, - nullptr, this->LocalGenerator); + cmGeneratorExpressionDAGChecker dagChecker( + this, "LINK_DEPENDS", nullptr, nullptr, this->LocalGenerator, config); EvaluatedTargetPropertyEntries entries; if (cmValue linkDepends = this->GetProperty("LINK_DEPENDS")) { diff --git a/Source/cmGeneratorTarget_Sources.cxx b/Source/cmGeneratorTarget_Sources.cxx index de18df5..94e8897 100644 --- a/Source/cmGeneratorTarget_Sources.cxx +++ b/Source/cmGeneratorTarget_Sources.cxx @@ -265,7 +265,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( } cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr, nullptr, - this->LocalGenerator); + this->LocalGenerator, config); EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( this, config, std::string(), &dagChecker, this->SourceEntries); diff --git a/Source/cmGeneratorTarget_TransitiveProperty.cxx b/Source/cmGeneratorTarget_TransitiveProperty.cxx index f5d9a1a..ac929eb 100644 --- a/Source/cmGeneratorTarget_TransitiveProperty.cxx +++ b/Source/cmGeneratorTarget_TransitiveProperty.cxx @@ -10,6 +10,7 @@ #include <utility> #include <vector> +#include <cm/memory> #include <cm/optional> #include <cm/string_view> #include <cmext/string_view> @@ -19,6 +20,7 @@ #include "cmGeneratorExpressionDAGChecker.h" #include "cmGeneratorExpressionNode.h" #include "cmLinkItem.h" +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmPolicies.h" #include "cmStringAlgorithms.h" @@ -107,9 +109,9 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty( // Evaluate $<TARGET_PROPERTY:this,prop> as if it were compiled. This is // a subset of TargetPropertyNode::Evaluate without stringify/parse steps // but sufficient for transitive interface properties. - cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, this, prop, - nullptr, dagCheckerParent, - this->LocalGenerator); + cmGeneratorExpressionDAGChecker dagChecker( + context->Backtrace, this, prop, nullptr, dagCheckerParent, + this->LocalGenerator, context->Config); switch (dagChecker.Check()) { case cmGeneratorExpressionDAGChecker::SELF_REFERENCE: dagChecker.ReportError( @@ -176,11 +178,16 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty( cm::optional<cmGeneratorTarget::TransitiveProperty> cmGeneratorTarget::IsTransitiveProperty(cm::string_view prop, - cmLocalGenerator const* lg) const + cmLocalGenerator const* lg, + std::string const& config, + bool evaluatingLinkLibraries) const { cm::optional<TransitiveProperty> result; static const cm::string_view kINTERFACE_ = "INTERFACE_"_s; - if (cmHasPrefix(prop, kINTERFACE_)) { + PropertyFor const propertyFor = cmHasPrefix(prop, kINTERFACE_) + ? PropertyFor::Interface + : PropertyFor::Build; + if (propertyFor == PropertyFor::Interface) { prop = prop.substr(kINTERFACE_.length()); } auto i = BuiltinTransitiveProperties.find(prop); @@ -202,6 +209,86 @@ cmGeneratorTarget::IsTransitiveProperty(cm::string_view prop, result = TransitiveProperty{ "INTERFACE_COMPILE_DEFINITIONS"_s, UseTo::Compile }; } + } else if (!evaluatingLinkLibraries) { + // Honor TRANSITIVE_COMPILE_PROPERTIES and TRANSITIVE_LINK_PROPERTIES + // from the link closure when we are not evaluating the closure itself. + CustomTransitiveProperties const& ctp = + this->GetCustomTransitiveProperties(config, propertyFor); + auto ci = ctp.find(std::string(prop)); + if (ci != ctp.end()) { + result = ci->second; + } } return result; } + +cmGeneratorTarget::CustomTransitiveProperty::CustomTransitiveProperty( + std::string interfaceName, UseTo usage) + : CustomTransitiveProperty( + cm::make_unique<std::string>(std::move(interfaceName)), usage) +{ +} +cmGeneratorTarget::CustomTransitiveProperty::CustomTransitiveProperty( + std::unique_ptr<std::string> interfaceNameBuf, UseTo usage) + : TransitiveProperty{ *interfaceNameBuf, usage } + , InterfaceNameBuf(std::move(interfaceNameBuf)) +{ +} + +void cmGeneratorTarget::CustomTransitiveProperties::Add(cmValue props, + UseTo usage) +{ + if (props) { + cmList propsList(*props); + for (std::string p : propsList) { + std::string ip; + static const cm::string_view kINTERFACE_ = "INTERFACE_"_s; + if (cmHasPrefix(p, kINTERFACE_)) { + ip = std::move(p); + p = ip.substr(kINTERFACE_.length()); + } else { + ip = cmStrCat(kINTERFACE_, p); + } + this->emplace(std::move(p), + CustomTransitiveProperty(std::move(ip), usage)); + } + } +} + +cmGeneratorTarget::CustomTransitiveProperties const& +cmGeneratorTarget::GetCustomTransitiveProperties(std::string const& config, + PropertyFor propertyFor) const +{ + std::map<std::string, CustomTransitiveProperties>& ctpm = + propertyFor == PropertyFor::Build + ? this->CustomTransitiveBuildPropertiesMap + : this->CustomTransitiveInterfacePropertiesMap; + auto i = ctpm.find(config); + if (i == ctpm.end()) { + CustomTransitiveProperties ctp; + auto addTransitiveProperties = [this, &config, propertyFor, + &ctp](std::string const& tp, UseTo usage) { + // Add transitive properties named by the target itself. + ctp.Add(this->GetProperty(tp), usage); + // Add transitive properties named by the target's link dependencies. + if (propertyFor == PropertyFor::Build) { + for (cmGeneratorTarget const* gt : + this->GetLinkImplementationClosure(config, usage)) { + ctp.Add(gt->GetProperty(tp), usage); + } + } else { + // The set of custom transitive INTERFACE_ properties does not + // depend on the consumer. Use the target as its own head. + cmGeneratorTarget const* headTarget = this; + for (cmGeneratorTarget const* gt : + this->GetLinkInterfaceClosure(config, headTarget, usage)) { + ctp.Add(gt->GetProperty(tp), usage); + } + } + }; + addTransitiveProperties("TRANSITIVE_LINK_PROPERTIES", UseTo::Link); + addTransitiveProperties("TRANSITIVE_COMPILE_PROPERTIES", UseTo::Compile); + i = ctpm.emplace(config, std::move(ctp)).first; + } + return i->second; +} diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 44af9ce..ee53a8e 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -1918,14 +1918,14 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() info.SetBool("MOC_RELAXED_MODE", this->Moc.RelaxedMode); info.SetBool("MOC_PATH_PREFIX", this->Moc.PathPrefix); - cmGeneratorExpressionDAGChecker dagChecker(this->GenTarget, - "AUTOMOC_MACRO_NAMES", nullptr, - nullptr, this->LocalGen); EvaluatedTargetPropertyEntries InterfaceAutoMocMacroNamesEntries; if (this->MultiConfig) { for (auto const& cfg : this->ConfigsList) { if (!cfg.empty()) { + cmGeneratorExpressionDAGChecker dagChecker( + this->GenTarget, "AUTOMOC_MACRO_NAMES", nullptr, nullptr, + this->LocalGen, cfg); AddInterfaceEntries(this->GenTarget, cfg, "INTERFACE_AUTOMOC_MACRO_NAMES", "CXX", &dagChecker, InterfaceAutoMocMacroNamesEntries, @@ -1933,6 +1933,9 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() } } } else { + cmGeneratorExpressionDAGChecker dagChecker( + this->GenTarget, "AUTOMOC_MACRO_NAMES", nullptr, nullptr, + this->LocalGen, this->ConfigDefault); AddInterfaceEntries(this->GenTarget, this->ConfigDefault, "INTERFACE_AUTOMOC_MACRO_NAMES", "CXX", &dagChecker, InterfaceAutoMocMacroNamesEntries, diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 9ff38bf..853380b 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -527,6 +527,7 @@ if(BUILD_TESTING) set_property(TEST CompileOptions APPEND PROPERTY LABELS "Fortran") ADD_TEST_MACRO(CompatibleInterface CompatibleInterface) + ADD_TEST_MACRO(CustomTransitiveProperties CustomTransitiveProperties) ADD_TEST_MACRO(AliasTarget AliasTarget) ADD_TEST_MACRO(StagingPrefix StagingPrefix) ADD_TEST_MACRO(ImportedSameName ImportedSameName) diff --git a/Tests/CustomTransitiveProperties/CMakeLists.txt b/Tests/CustomTransitiveProperties/CMakeLists.txt new file mode 100644 index 0000000..83ceff5 --- /dev/null +++ b/Tests/CustomTransitiveProperties/CMakeLists.txt @@ -0,0 +1,146 @@ +cmake_minimum_required(VERSION 3.29) +cmake_policy(SET CMP0166 NEW) +project(CustomTransitiveProperties C) + +add_library(iface1 INTERFACE) +set_target_properties(iface1 PROPERTIES + TRANSITIVE_COMPILE_PROPERTIES "CUSTOM_A" # LINK_ONLY not pierced + TRANSITIVE_LINK_PROPERTIES "CUSTOM_U" # LINK_ONLY pierced + + INTERFACE_CUSTOM_A "CUSTOM_A_IFACE1;CUSTOM_A_TARGET_NAME_$<UPPER_CASE:$<TARGET_PROPERTY:NAME>>" + INTERFACE_CUSTOM_B "CUSTOM_B_IFACE1" + INTERFACE_CUSTOM_C "CUSTOM_C_IFACE1" + INTERFACE_CUSTOM_U "CUSTOM_U_IFACE1;CUSTOM_U_TARGET_NAME_$<UPPER_CASE:$<TARGET_PROPERTY:NAME>>" + INTERFACE_CUSTOM_V "CUSTOM_V_IFACE1" + INTERFACE_CUSTOM_W "CUSTOM_W_IFACE1" + ) + +add_library(iface2 INTERFACE) +set_target_properties(iface2 PROPERTIES + INTERFACE_CUSTOM_A "CUSTOM_A_IFACE2;CUSTOM_A_TARGET_TYPE_$<TARGET_PROPERTY:TYPE>" + INTERFACE_CUSTOM_U "CUSTOM_U_IFACE2;CUSTOM_U_TARGET_TYPE_$<TARGET_PROPERTY:TYPE>" + ) +target_link_libraries(iface2 INTERFACE iface1) + +# Test that the INTERFACE prefix is removed. +set(unnecessary_INTERFACE_ "INTERFACE_") + +add_library(static1 STATIC static1.c) +target_link_libraries(static1 PRIVATE iface2) +set_target_properties(static1 PROPERTIES + TRANSITIVE_COMPILE_PROPERTIES "${unnecessary_INTERFACE_}CUSTOM_B" # LINK_ONLY not pierced + TRANSITIVE_LINK_PROPERTIES "${unnecessary_INTERFACE_}CUSTOM_V" # LINK_ONLY pierced + + CUSTOM_A "CUSTOM_A_STATIC1" + CUSTOM_B "CUSTOM_B_STATIC1" + CUSTOM_U "CUSTOM_U_STATIC1" + CUSTOM_V "CUSTOM_V_STATIC1" + INTERFACE_CUSTOM_A "CUSTOM_A_STATIC1_IFACE" + INTERFACE_CUSTOM_B "CUSTOM_B_STATIC1_IFACE" + INTERFACE_CUSTOM_U "CUSTOM_U_STATIC1_IFACE" + INTERFACE_CUSTOM_V "CUSTOM_V_STATIC1_IFACE" + ) +target_compile_definitions(static1 PRIVATE + $<TARGET_PROPERTY:CUSTOM_A> + $<TARGET_PROPERTY:CUSTOM_B> + $<TARGET_PROPERTY:CUSTOM_U> + $<TARGET_PROPERTY:CUSTOM_V> + ) + +add_library(object1 OBJECT object1.c) +target_link_libraries(object1 PRIVATE iface2) +set_target_properties(object1 PROPERTIES + TRANSITIVE_COMPILE_PROPERTIES "${unnecessary_INTERFACE_}CUSTOM_C" # LINK_ONLY not pierced + TRANSITIVE_LINK_PROPERTIES "${unnecessary_INTERFACE_}CUSTOM_W" # LINK_ONLY pierced + + CUSTOM_A "CUSTOM_A_OBJECT1" + CUSTOM_C "CUSTOM_C_OBJECT1" + CUSTOM_U "CUSTOM_U_OBJECT1" + CUSTOM_W "CUSTOM_W_OBJECT1" + INTERFACE_CUSTOM_A "CUSTOM_A_OBJECT1_IFACE" + INTERFACE_CUSTOM_C "CUSTOM_C_OBJECT1_IFACE" + INTERFACE_CUSTOM_U "CUSTOM_U_OBJECT1_IFACE" + INTERFACE_CUSTOM_W "CUSTOM_W_OBJECT1_IFACE" + ) +target_compile_definitions(object1 PRIVATE + $<TARGET_PROPERTY:CUSTOM_A> + $<TARGET_PROPERTY:CUSTOM_C> + $<TARGET_PROPERTY:CUSTOM_U> + $<TARGET_PROPERTY:CUSTOM_W> + ) + +add_executable(CustomTransitiveProperties main.c) +target_link_libraries(CustomTransitiveProperties PRIVATE static1 object1) +set_target_properties(CustomTransitiveProperties PROPERTIES + CUSTOM_A "CUSTOM_A_MAIN" + CUSTOM_B "CUSTOM_B_MAIN" + CUSTOM_C "CUSTOM_C_MAIN" + CUSTOM_U "CUSTOM_U_MAIN" + CUSTOM_V "CUSTOM_V_MAIN" + CUSTOM_W "CUSTOM_W_MAIN" + ) + +# Test TRANSITIVE_*_PROPERTY evaluation within usage requirements. +target_compile_definitions(CustomTransitiveProperties PRIVATE + $<TARGET_PROPERTY:CUSTOM_A> + $<TARGET_PROPERTY:CUSTOM_B> + $<TARGET_PROPERTY:CUSTOM_C> + $<TARGET_PROPERTY:CUSTOM_U> + $<TARGET_PROPERTY:CUSTOM_V> + $<TARGET_PROPERTY:CUSTOM_W> + ) + +# Test TRANSITIVE_*_PROPERTY evaluation outside of usage requirements. +set(out "${CMAKE_CURRENT_BINARY_DIR}/out-$<CONFIG>.txt") +file(GENERATE OUTPUT "${out}" CONTENT "# file(GENERATE) produced: +iface1 CUSTOM_A: '$<TARGET_PROPERTY:iface1,CUSTOM_A>' +iface1 INTERFACE_CUSTOM_A: '$<TARGET_PROPERTY:iface1,INTERFACE_CUSTOM_A>' +iface2 CUSTOM_A: '$<TARGET_PROPERTY:iface2,CUSTOM_A>' +iface2 INTERFACE_CUSTOM_A: '$<TARGET_PROPERTY:iface2,INTERFACE_CUSTOM_A>' +static1 CUSTOM_A: '$<TARGET_PROPERTY:static1,CUSTOM_A>' +static1 INTERFACE_CUSTOM_A: '$<TARGET_PROPERTY:static1,INTERFACE_CUSTOM_A>' +static1 CUSTOM_B: '$<TARGET_PROPERTY:static1,CUSTOM_B>' +static1 INTERFACE_CUSTOM_B: '$<TARGET_PROPERTY:static1,INTERFACE_CUSTOM_B>' +static1 CUSTOM_U: '$<TARGET_PROPERTY:static1,CUSTOM_U>' +static1 INTERFACE_CUSTOM_U: '$<TARGET_PROPERTY:static1,INTERFACE_CUSTOM_U>' +static1 CUSTOM_V: '$<TARGET_PROPERTY:static1,CUSTOM_V>' +static1 INTERFACE_CUSTOM_V: '$<TARGET_PROPERTY:static1,INTERFACE_CUSTOM_V>' +object1 CUSTOM_A: '$<TARGET_PROPERTY:object1,CUSTOM_A>' +object1 INTERFACE_CUSTOM_A: '$<TARGET_PROPERTY:object1,INTERFACE_CUSTOM_A>' +object1 CUSTOM_C: '$<TARGET_PROPERTY:object1,CUSTOM_C>' +object1 INTERFACE_CUSTOM_C: '$<TARGET_PROPERTY:object1,INTERFACE_CUSTOM_C>' +object1 CUSTOM_U: '$<TARGET_PROPERTY:object1,CUSTOM_U>' +object1 INTERFACE_CUSTOM_U: '$<TARGET_PROPERTY:object1,INTERFACE_CUSTOM_U>' +object1 CUSTOM_W: '$<TARGET_PROPERTY:object1,CUSTOM_W>' +object1 INTERFACE_CUSTOM_W: '$<TARGET_PROPERTY:object1,INTERFACE_CUSTOM_W>' +main CUSTOM_A: '$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_A>' +main INTERFACE_CUSTOM_A: '$<TARGET_PROPERTY:CustomTransitiveProperties,INTERFACE_CUSTOM_A>' +main CUSTOM_B: '$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_B>' +main INTERFACE_CUSTOM_B: '$<TARGET_PROPERTY:CustomTransitiveProperties,INTERFACE_CUSTOM_B>' +main CUSTOM_C: '$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_C>' +main INTERFACE_CUSTOM_C: '$<TARGET_PROPERTY:CustomTransitiveProperties,INTERFACE_CUSTOM_C>' +main CUSTOM_U: '$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_U>' +main INTERFACE_CUSTOM_U: '$<TARGET_PROPERTY:CustomTransitiveProperties,INTERFACE_CUSTOM_U>' +main CUSTOM_V: '$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_V>' +main INTERFACE_CUSTOM_V: '$<TARGET_PROPERTY:CustomTransitiveProperties,INTERFACE_CUSTOM_V>' +main CUSTOM_W: '$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_W>' +main INTERFACE_CUSTOM_W: '$<TARGET_PROPERTY:CustomTransitiveProperties,INTERFACE_CUSTOM_W>' +") +add_custom_target(check ALL VERBATIM + COMMAND ${CMAKE_COMMAND} -Dconfig=$<CONFIG> -Dout=${out} -P${CMAKE_CURRENT_SOURCE_DIR}/check.cmake + COMMAND CustomTransitiveProperties + "$<TARGET_PROPERTY:static1,CUSTOM_A>" "CUSTOM_A_STATIC1;CUSTOM_A_IFACE2;CUSTOM_A_TARGET_TYPE_STATIC_LIBRARY;CUSTOM_A_IFACE1;CUSTOM_A_TARGET_NAME_STATIC1" + "$<TARGET_PROPERTY:static1,CUSTOM_B>" "CUSTOM_B_STATIC1;CUSTOM_B_IFACE1" + "$<TARGET_PROPERTY:static1,CUSTOM_U>" "CUSTOM_U_STATIC1;CUSTOM_U_IFACE2;CUSTOM_U_TARGET_TYPE_STATIC_LIBRARY;CUSTOM_U_IFACE1;CUSTOM_U_TARGET_NAME_STATIC1" + "$<TARGET_PROPERTY:static1,CUSTOM_V>" "CUSTOM_V_STATIC1;CUSTOM_V_IFACE1" + "$<TARGET_PROPERTY:object1,CUSTOM_A>" "CUSTOM_A_OBJECT1;CUSTOM_A_IFACE2;CUSTOM_A_TARGET_TYPE_OBJECT_LIBRARY;CUSTOM_A_IFACE1;CUSTOM_A_TARGET_NAME_OBJECT1" + "$<TARGET_PROPERTY:object1,CUSTOM_C>" "CUSTOM_C_OBJECT1;CUSTOM_C_IFACE1" + "$<TARGET_PROPERTY:object1,CUSTOM_U>" "CUSTOM_U_OBJECT1;CUSTOM_U_IFACE2;CUSTOM_U_TARGET_TYPE_OBJECT_LIBRARY;CUSTOM_U_IFACE1;CUSTOM_U_TARGET_NAME_OBJECT1" + "$<TARGET_PROPERTY:object1,CUSTOM_W>" "CUSTOM_W_OBJECT1;CUSTOM_W_IFACE1" + "$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_A>" "CUSTOM_A_MAIN" + "$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_B>" "CUSTOM_B_MAIN;CUSTOM_B_STATIC1_IFACE" + "$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_C>" "CUSTOM_C_MAIN;CUSTOM_C_OBJECT1_IFACE" + "$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_U>" "CUSTOM_U_MAIN;CUSTOM_U_STATIC1_IFACE;CUSTOM_U_IFACE2;CUSTOM_U_TARGET_TYPE_EXECUTABLE;CUSTOM_U_IFACE1;CUSTOM_U_TARGET_NAME_CUSTOMTRANSITIVEPROPERTIES;CUSTOM_U_OBJECT1_IFACE" + "$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_V>" "CUSTOM_V_MAIN;CUSTOM_V_STATIC1_IFACE;CUSTOM_V_IFACE1" + "$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_W>" "CUSTOM_W_MAIN;CUSTOM_W_IFACE1;CUSTOM_W_OBJECT1_IFACE" + ) diff --git a/Tests/CustomTransitiveProperties/check.cmake b/Tests/CustomTransitiveProperties/check.cmake new file mode 100644 index 0000000..d7130c8 --- /dev/null +++ b/Tests/CustomTransitiveProperties/check.cmake @@ -0,0 +1,47 @@ +set(expect [[ +# file\(GENERATE\) produced: +iface1 CUSTOM_A: '' +iface1 INTERFACE_CUSTOM_A: 'CUSTOM_A_IFACE1;CUSTOM_A_TARGET_NAME_IFACE1' +iface2 CUSTOM_A: '' +iface2 INTERFACE_CUSTOM_A: 'CUSTOM_A_IFACE2;CUSTOM_A_TARGET_TYPE_INTERFACE_LIBRARY;CUSTOM_A_IFACE1;CUSTOM_A_TARGET_NAME_IFACE2' +static1 CUSTOM_A: 'CUSTOM_A_STATIC1;CUSTOM_A_IFACE2;CUSTOM_A_TARGET_TYPE_STATIC_LIBRARY;CUSTOM_A_IFACE1;CUSTOM_A_TARGET_NAME_STATIC1' +static1 INTERFACE_CUSTOM_A: 'CUSTOM_A_STATIC1_IFACE' +static1 CUSTOM_B: 'CUSTOM_B_STATIC1;CUSTOM_B_IFACE1' +static1 INTERFACE_CUSTOM_B: 'CUSTOM_B_STATIC1_IFACE' +static1 CUSTOM_U: 'CUSTOM_U_STATIC1;CUSTOM_U_IFACE2;CUSTOM_U_TARGET_TYPE_STATIC_LIBRARY;CUSTOM_U_IFACE1;CUSTOM_U_TARGET_NAME_STATIC1' +static1 INTERFACE_CUSTOM_U: 'CUSTOM_U_STATIC1_IFACE;CUSTOM_U_IFACE2;CUSTOM_U_TARGET_TYPE_STATIC_LIBRARY;CUSTOM_U_IFACE1;CUSTOM_U_TARGET_NAME_STATIC1' +static1 CUSTOM_V: 'CUSTOM_V_STATIC1;CUSTOM_V_IFACE1' +static1 INTERFACE_CUSTOM_V: 'CUSTOM_V_STATIC1_IFACE;CUSTOM_V_IFACE1' +object1 CUSTOM_A: 'CUSTOM_A_OBJECT1;CUSTOM_A_IFACE2;CUSTOM_A_TARGET_TYPE_OBJECT_LIBRARY;CUSTOM_A_IFACE1;CUSTOM_A_TARGET_NAME_OBJECT1' +object1 INTERFACE_CUSTOM_A: 'CUSTOM_A_OBJECT1_IFACE' +object1 CUSTOM_C: 'CUSTOM_C_OBJECT1;CUSTOM_C_IFACE1' +object1 INTERFACE_CUSTOM_C: 'CUSTOM_C_OBJECT1_IFACE' +object1 CUSTOM_U: 'CUSTOM_U_OBJECT1;CUSTOM_U_IFACE2;CUSTOM_U_TARGET_TYPE_OBJECT_LIBRARY;CUSTOM_U_IFACE1;CUSTOM_U_TARGET_NAME_OBJECT1' +object1 INTERFACE_CUSTOM_U: 'CUSTOM_U_OBJECT1_IFACE;CUSTOM_U_IFACE2;CUSTOM_U_TARGET_TYPE_OBJECT_LIBRARY;CUSTOM_U_IFACE1;CUSTOM_U_TARGET_NAME_OBJECT1' +object1 CUSTOM_W: 'CUSTOM_W_OBJECT1;CUSTOM_W_IFACE1' +object1 INTERFACE_CUSTOM_W: 'CUSTOM_W_OBJECT1_IFACE;CUSTOM_W_IFACE1' +main CUSTOM_A: 'CUSTOM_A_MAIN' +main INTERFACE_CUSTOM_A: '' +main CUSTOM_B: 'CUSTOM_B_MAIN;CUSTOM_B_STATIC1_IFACE' +main INTERFACE_CUSTOM_B: '' +main CUSTOM_C: 'CUSTOM_C_MAIN;CUSTOM_C_OBJECT1_IFACE' +main INTERFACE_CUSTOM_C: '' +main CUSTOM_U: 'CUSTOM_U_MAIN;CUSTOM_U_STATIC1_IFACE;CUSTOM_U_IFACE2;CUSTOM_U_TARGET_TYPE_EXECUTABLE;CUSTOM_U_IFACE1;CUSTOM_U_TARGET_NAME_CUSTOMTRANSITIVEPROPERTIES;CUSTOM_U_OBJECT1_IFACE' +main INTERFACE_CUSTOM_U: '' +main CUSTOM_V: 'CUSTOM_V_MAIN;CUSTOM_V_STATIC1_IFACE;CUSTOM_V_IFACE1' +main INTERFACE_CUSTOM_V: '' +main CUSTOM_W: 'CUSTOM_W_MAIN;CUSTOM_W_IFACE1;CUSTOM_W_OBJECT1_IFACE' +main INTERFACE_CUSTOM_W: '' +]]) +string(REGEX REPLACE "\r\n" "\n" expect "${expect}") +string(REGEX REPLACE "\n+$" "" expect "${expect}") + +file(READ "${out}" actual) +string(REGEX REPLACE "\r\n" "\n" actual "${actual}") +string(REGEX REPLACE "\n+$" "" actual "${actual}") + +if(NOT actual MATCHES "^${expect}$") + string(REPLACE "\n" "\n expect> " expect " expect> ${expect}") + string(REPLACE "\n" "\n actual> " actual " actual> ${actual}") + message(FATAL_ERROR "Expected file(GENERATE) output:\n${expect}\ndoes not match actual output:\n${actual}") +endif() diff --git a/Tests/CustomTransitiveProperties/main.c b/Tests/CustomTransitiveProperties/main.c new file mode 100644 index 0000000..ab70eb0 --- /dev/null +++ b/Tests/CustomTransitiveProperties/main.c @@ -0,0 +1,137 @@ +#include <stdio.h> +#include <string.h> + +#ifdef CUSTOM_A_IFACE1 +# error "CUSTOM_A_IFACE1 incorrectly defined" +#endif + +#ifdef CUSTOM_A_IFACE2 +# error "CUSTOM_A_IFACE2 incorrectly defined" +#endif + +#ifdef CUSTOM_A_STATIC1_IFACE +# error "CUSTOM_A_STATIC1_IFACE incorrectly defined" +#endif + +#ifdef CUSTOM_A_OBJECT1_IFACE +# error "CUSTOM_A_OBJECT1_IFACE incorrectly defined" +#endif + +#ifndef CUSTOM_A_MAIN +# error "CUSTOM_A_MAIN incorrectly not defined" +#endif + +#ifdef CUSTOM_B_IFACE1 +# error "CUSTOM_B_IFACE1 incorrectly defined" +#endif + +#ifndef CUSTOM_B_STATIC1_IFACE +# error "CUSTOM_B_STATIC1_IFACE incorrectly not defined" +#endif + +#ifndef CUSTOM_B_MAIN +# error "CUSTOM_B_MAIN incorrectly not defined" +#endif + +#ifdef CUSTOM_C_IFACE1 +# error "CUSTOM_C_IFACE1 incorrectly defined" +#endif + +#ifndef CUSTOM_C_OBJECT1_IFACE +# error "CUSTOM_C_OBJECT1_IFACE incorrectly not defined" +#endif + +#ifndef CUSTOM_C_MAIN +# error "CUSTOM_C_MAIN incorrectly not defined" +#endif + +#ifndef CUSTOM_U_IFACE1 +# error "CUSTOM_U_IFACE1 incorrectly not defined" +#endif + +#ifndef CUSTOM_U_IFACE2 +# error "CUSTOM_U_IFACE2 incorrectly not defined" +#endif + +#ifndef CUSTOM_U_MAIN +# error "CUSTOM_U_MAIN incorrectly not defined" +#endif + +#ifdef CUSTOM_U_STATIC1 +# error "CUSTOM_U_STATIC1 incorrectly defined" +#endif + +#ifndef CUSTOM_U_STATIC1_IFACE +# error "CUSTOM_U_STATIC1_IFACE incorrectly not defined" +#endif + +#ifdef CUSTOM_U_OBJECT1 +# error "CUSTOM_U_OBJECT1 incorrectly defined" +#endif + +#ifndef CUSTOM_U_OBJECT1_IFACE +# error "CUSTOM_U_OBJECT1_IFACE incorrectly not defined" +#endif + +#ifndef CUSTOM_U_TARGET_NAME_CUSTOMTRANSITIVEPROPERTIES +# error \ + "CUSTOM_U_TARGET_NAME_CUSTOMTRANSITIVEPROPERTIES incorrectly not defined" +#endif + +#ifndef CUSTOM_U_TARGET_TYPE_EXECUTABLE +# error "CUSTOM_U_TARGET_TYPE_EXECUTABLE incorrectly not defined" +#endif + +#ifndef CUSTOM_V_IFACE1 +# error "CUSTOM_V_IFACE1 incorrectly not defined" +#endif + +#ifndef CUSTOM_V_MAIN +# error "CUSTOM_V_MAIN incorrectly not defined" +#endif + +#ifdef CUSTOM_V_STATIC1 +# error "CUSTOM_V_STATIC1 incorrectly defined" +#endif + +#ifndef CUSTOM_V_STATIC1_IFACE +# error "CUSTOM_V_STATIC1_IFACE incorrectly not defined" +#endif + +#ifndef CUSTOM_W_IFACE1 +# error "CUSTOM_W_IFACE1 incorrectly not defined" +#endif + +#ifndef CUSTOM_W_MAIN +# error "CUSTOM_W_MAIN incorrectly not defined" +#endif + +#ifdef CUSTOM_W_OBJECT1 +# error "CUSTOM_W_OBJECT1 incorrectly defined" +#endif + +#ifndef CUSTOM_W_OBJECT1_IFACE +# error "CUSTOM_W_OBJECT1_IFACE incorrectly not defined" +#endif + +extern int static1(void); +extern int object1(void); + +int check_args(int argc, char** argv) +{ + int result = 0; + int i; + for (i = 2; i < argc; i += 2) { + if (strcmp(argv[i - 1], argv[i]) != 0) { + fprintf(stderr, "Argument %d expected '%s' but got '%s'.\n", i, argv[i], + argv[i - 1]); + result = 1; + } + } + return result; +} + +int main(int argc, char** argv) +{ + return static1() + object1() + check_args(argc, argv); +} diff --git a/Tests/CustomTransitiveProperties/object1.c b/Tests/CustomTransitiveProperties/object1.c new file mode 100644 index 0000000..4454118 --- /dev/null +++ b/Tests/CustomTransitiveProperties/object1.c @@ -0,0 +1,64 @@ +#ifndef CUSTOM_A_IFACE1 +# error "CUSTOM_A_IFACE1 incorrectly not defined" +#endif + +#ifndef CUSTOM_A_IFACE2 +# error "CUSTOM_A_IFACE2 incorrectly not defined" +#endif + +#ifndef CUSTOM_A_OBJECT1 +# error "CUSTOM_A_OBJECT1 incorrectly not defined" +#endif + +#ifndef CUSTOM_A_TARGET_NAME_OBJECT1 +# error "CUSTOM_A_TARGET_NAME_OBJECT1 incorrectly not defined" +#endif + +#ifndef CUSTOM_A_TARGET_TYPE_OBJECT_LIBRARY +# error "CUSTOM_A_TARGET_TYPE_OBJECT_LIBRARY incorrectly not defined" +#endif + +#ifndef CUSTOM_C_IFACE1 +# error "CUSTOM_C_IFACE1 incorrectly not defined" +#endif + +#ifndef CUSTOM_C_OBJECT1 +# error "CUSTOM_C_OBJECT1 incorrectly not defined" +#endif + +#ifdef CUSTOM_C_OBJECT1_IFACE +# error "CUSTOM_C_OBJECT1_IFACE incorrectly defined" +#endif + +#ifndef CUSTOM_U_IFACE1 +# error "CUSTOM_U_IFACE1 incorrectly not defined" +#endif + +#ifndef CUSTOM_U_IFACE2 +# error "CUSTOM_U_IFACE2 incorrectly not defined" +#endif + +#ifndef CUSTOM_U_OBJECT1 +# error "CUSTOM_U_OBJECT1 incorrectly not defined" +#endif + +#ifndef CUSTOM_U_TARGET_NAME_OBJECT1 +# error "CUSTOM_U_TARGET_NAME_OBJECT1 incorrectly not defined" +#endif + +#ifndef CUSTOM_U_TARGET_TYPE_OBJECT_LIBRARY +# error "CUSTOM_U_TARGET_TYPE_OBJECT_LIBRARY incorrectly not defined" +#endif + +#ifndef CUSTOM_W_IFACE1 +# error "CUSTOM_W_IFACE1 incorrectly not defined" +#endif + +#ifndef CUSTOM_W_OBJECT1 +# error "CUSTOM_W_OBJECT1 incorrectly not defined" +#endif + +int object1(void) +{ + return 0; +} diff --git a/Tests/CustomTransitiveProperties/static1.c b/Tests/CustomTransitiveProperties/static1.c new file mode 100644 index 0000000..45e9507 --- /dev/null +++ b/Tests/CustomTransitiveProperties/static1.c @@ -0,0 +1,64 @@ +#ifndef CUSTOM_A_IFACE1 +# error "CUSTOM_A_IFACE1 incorrectly not defined" +#endif + +#ifndef CUSTOM_A_IFACE2 +# error "CUSTOM_A_IFACE2 incorrectly not defined" +#endif + +#ifndef CUSTOM_A_STATIC1 +# error "CUSTOM_A_STATIC1 incorrectly not defined" +#endif + +#ifndef CUSTOM_A_TARGET_NAME_STATIC1 +# error "CUSTOM_A_TARGET_NAME_STATIC1 incorrectly not defined" +#endif + +#ifndef CUSTOM_A_TARGET_TYPE_STATIC_LIBRARY +# error "CUSTOM_A_TARGET_TYPE_STATIC_LIBRARY incorrectly not defined" +#endif + +#ifndef CUSTOM_B_IFACE1 +# error "CUSTOM_B_IFACE1 incorrectly not defined" +#endif + +#ifndef CUSTOM_B_STATIC1 +# error "CUSTOM_B_STATIC1 incorrectly not defined" +#endif + +#ifdef CUSTOM_B_STATIC1_IFACE +# error "CUSTOM_B_STATIC1_IFACE incorrectly defined" +#endif + +#ifndef CUSTOM_U_IFACE1 +# error "CUSTOM_U_IFACE1 incorrectly not defined" +#endif + +#ifndef CUSTOM_U_IFACE2 +# error "CUSTOM_U_IFACE2 incorrectly not defined" +#endif + +#ifndef CUSTOM_U_STATIC1 +# error "CUSTOM_U_STATIC1 incorrectly not defined" +#endif + +#ifndef CUSTOM_U_TARGET_NAME_STATIC1 +# error "CUSTOM_U_TARGET_NAME_STATIC1 incorrectly not defined" +#endif + +#ifndef CUSTOM_U_TARGET_TYPE_STATIC_LIBRARY +# error "CUSTOM_U_TARGET_TYPE_STATIC_LIBRARY incorrectly not defined" +#endif + +#ifndef CUSTOM_V_IFACE1 +# error "CUSTOM_V_IFACE1 incorrectly not defined" +#endif + +#ifndef CUSTOM_V_STATIC1 +# error "CUSTOM_V_STATIC1 incorrectly not defined" +#endif + +int static1(void) +{ + return 0; +} diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt index 0b7f739..8f83587 100644 --- a/Tests/ExportImport/Export/CMakeLists.txt +++ b/Tests/ExportImport/Export/CMakeLists.txt @@ -116,6 +116,37 @@ target_link_libraries(testLib9 INTERFACE testLib9ObjIface PUBLIC testLib9ObjPub target_link_libraries(testLib9 PUBLIC Foo::Foo) cmake_policy(POP) +block() + cmake_policy(SET CMP0022 NEW) + add_library(testLib10 STATIC testLib10.c) + set_target_properties(testLib10 PROPERTIES + TRANSITIVE_COMPILE_PROPERTIES "CUSTOM_C" + TRANSITIVE_LINK_PROPERTIES "CUSTOM_L" + INTERFACE_CUSTOM_C "TESTLIB10_INTERFACE_CUSTOM_C" + INTERFACE_CUSTOM_L "TESTLIB10_INTERFACE_CUSTOM_L" + ) + target_compile_definitions(testLib10 INTERFACE + "$<TARGET_PROPERTY:CUSTOM_C>" + "$<TARGET_PROPERTY:CUSTOM_L>" + ) + add_library(testLib11 STATIC testLib11.c) + target_link_libraries(testLib11 PRIVATE testLib10) + set_target_properties(testLib11 PROPERTIES + INTERFACE_CUSTOM_C "TESTLIB11_INTERFACE_CUSTOM_C" + INTERFACE_CUSTOM_L "TESTLIB11_INTERFACE_CUSTOM_L" + TRANSITIVE_COMPILE_PROPERTIES "CUSTOM_D" + TRANSITIVE_LINK_PROPERTIES "CUSTOM_M" + INTERFACE_CUSTOM_D "TESTLIB11_INTERFACE_CUSTOM_D" + INTERFACE_CUSTOM_M "TESTLIB11_INTERFACE_CUSTOM_M" + ) + target_compile_definitions(testLib11 INTERFACE + "$<TARGET_PROPERTY:CUSTOM_C>" + "$<TARGET_PROPERTY:CUSTOM_D>" + "$<TARGET_PROPERTY:CUSTOM_L>" + "$<TARGET_PROPERTY:CUSTOM_M>" + ) +endblock() + # Test using the target_link_libraries command to set the # LINK_INTERFACE_LIBRARIES* properties. We construct two libraries # providing the same two symbols. In each library one of the symbols @@ -574,6 +605,7 @@ install( testExe2lib testLib4lib testLib4libdbg testLib4libopt testLib6 testLib7 testLib8 testLib9 + testLib10 testLib11 testLibDeprecation testLibCycleA testLibCycleB testLibNoSONAME @@ -653,6 +685,7 @@ export(TARGETS testExe1 testLib1 testLib2 testLib3 export(TARGETS testExe2 testLib4 testLib5 testLib6 testLib7 testExe3 testExe4 testExe2lib testLib8 testLib9 testLib9ObjPub testLib9ObjPriv testLib9ObjIface + testLib10 testLib11 testLibDeprecation testLib4lib testLib4libdbg testLib4libopt testLibCycleA testLibCycleB diff --git a/Tests/ExportImport/Export/testLib10.c b/Tests/ExportImport/Export/testLib10.c new file mode 100644 index 0000000..d5ecb7f --- /dev/null +++ b/Tests/ExportImport/Export/testLib10.c @@ -0,0 +1,4 @@ +int testLib10(void) +{ + return 0; +} diff --git a/Tests/ExportImport/Export/testLib11.c b/Tests/ExportImport/Export/testLib11.c new file mode 100644 index 0000000..b288b29 --- /dev/null +++ b/Tests/ExportImport/Export/testLib11.c @@ -0,0 +1,6 @@ +int testLib10(void); + +int testLib11(void) +{ + return testLib10(); +} diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt index 2a57633..632825d 100644 --- a/Tests/ExportImport/Import/A/CMakeLists.txt +++ b/Tests/ExportImport/Import/A/CMakeLists.txt @@ -328,6 +328,16 @@ foreach(vis Pub Priv Iface) endif() endforeach() +# Create executables to verify custom transitive properties. +add_executable(imp_testLib10 imp_testLib10.c) +target_link_libraries(imp_testLib10 PRIVATE exp_testLib10) +add_executable(imp_testLib10b imp_testLib10.c) +target_link_libraries(imp_testLib10b PRIVATE bld_testLib10) +add_executable(imp_testLib11 imp_testLib11.c) +target_link_libraries(imp_testLib11 PRIVATE exp_testLib11) +add_executable(imp_testLib11b imp_testLib11.c) +target_link_libraries(imp_testLib11b PRIVATE bld_testLib11) + #----------------------------------------------------------------------------- # Test that handling imported targets, including transitive dependencies, # works in CheckFunctionExists (...and hopefully all other try_compile() checks diff --git a/Tests/ExportImport/Import/A/imp_testLib10.c b/Tests/ExportImport/Import/A/imp_testLib10.c new file mode 100644 index 0000000..5d6e823 --- /dev/null +++ b/Tests/ExportImport/Import/A/imp_testLib10.c @@ -0,0 +1,14 @@ +#ifndef TESTLIB10_INTERFACE_CUSTOM_C +# error "TESTLIB10_INTERFACE_CUSTOM_C incorrectly not defined!" +#endif + +#ifndef TESTLIB10_INTERFACE_CUSTOM_L +# error "TESTLIB10_INTERFACE_CUSTOM_L incorrectly not defined!" +#endif + +int testLib10(void); + +int main(void) +{ + return testLib10(); +} diff --git a/Tests/ExportImport/Import/A/imp_testLib11.c b/Tests/ExportImport/Import/A/imp_testLib11.c new file mode 100644 index 0000000..e8e10e6 --- /dev/null +++ b/Tests/ExportImport/Import/A/imp_testLib11.c @@ -0,0 +1,30 @@ +#ifdef TESTLIB10_INTERFACE_CUSTOM_C +# error "TESTLIB10_INTERFACE_CUSTOM_C incorrectly defined!" +#endif + +#ifdef TESTLIB11_INTERFACE_CUSTOM_C +# error "TESTLIB11_INTERFACE_CUSTOM_C incorrectly defined!" +#endif + +#ifndef TESTLIB11_INTERFACE_CUSTOM_D +# error "TESTLIB11_INTERFACE_CUSTOM_D incorrectly not defined!" +#endif + +#ifndef TESTLIB10_INTERFACE_CUSTOM_L +# error "TESTLIB10_INTERFACE_CUSTOM_L incorrectly not defined!" +#endif + +#ifndef TESTLIB11_INTERFACE_CUSTOM_L +# error "TESTLIB11_INTERFACE_CUSTOM_L incorrectly not defined!" +#endif + +#ifndef TESTLIB11_INTERFACE_CUSTOM_M +# error "TESTLIB11_INTERFACE_CUSTOM_M incorrectly not defined!" +#endif + +int testLib11(void); + +int main(void) +{ + return testLib11(); +} |