summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2024-05-01 14:05:53 (GMT)
committerKitware Robot <kwrobot@kitware.com>2024-05-01 14:06:11 (GMT)
commitde9faaf0a318d05b694d0edebedfab84e820fe51 (patch)
treeddfdb25866c37ddbbee6a8b0a474c60fb1c73939
parent30b61287adfac023820c2d6ca70d96216fe226b5 (diff)
parentddb9442f487808b74ed3429832a74385a1214582 (diff)
downloadCMake-de9faaf0a318d05b694d0edebedfab84e820fe51.zip
CMake-de9faaf0a318d05b694d0edebedfab84e820fe51.tar.gz
CMake-de9faaf0a318d05b694d0edebedfab84e820fe51.tar.bz2
Merge topic 'genex-link-properties'
ddb9442f48 GenEx: Fix TARGET_PROPERTY evaluation of transitive link properties 862b8e28ad GenEx: Teach TARGET_PROPERTY evaluation to optionally pierce LINK_ONLY 8d1d6a1437 Tests: Cover TARGET_PROPERTY genex evaluation of transitive link properties abf607c2ec Tests: Cover TARGET_PROPERTY genex evaluation of transitive build properties 7d3d728a72 Help: Clarify CMP0099 documentation and summary text 79a3ae9a0d cmGeneratorExpressionDAGChecker: Simplify transitive property table e8010b67c7 cmGeneratorExpressionDAGChecker: Make local generator available in constructor b36fb3f6f1 cmGeneratorExpressionNode: Remove outdated lint suppression Acked-by: Kitware Robot <kwrobot@kitware.com> Tested-by: buildbot <buildbot@kitware.com> Merge-request: !9473
-rw-r--r--Help/manual/cmake-generator-expressions.7.rst17
-rw-r--r--Help/manual/cmake-policies.7.rst3
-rw-r--r--Help/policy/CMP0099.rst19
-rw-r--r--Help/policy/CMP0166.rst40
-rw-r--r--Help/release/dev/genex-link-properties.rst8
-rw-r--r--Source/cmCommonTargetGenerator.cxx3
-rw-r--r--Source/cmComputeLinkDepends.cxx21
-rw-r--r--Source/cmExportTryCompileFileGenerator.cxx18
-rw-r--r--Source/cmGeneratorExpression.cxx2
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.cxx58
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.h40
-rw-r--r--Source/cmGeneratorExpressionNode.cxx48
-rw-r--r--Source/cmGeneratorTarget.cxx117
-rw-r--r--Source/cmGeneratorTarget.h13
-rw-r--r--Source/cmPolicies.h10
-rw-r--r--Source/cmQtAutoGenInitializer.cxx5
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt4
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild-check.cmake25
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild.cmake66
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-check.cmake8
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW.cmake2
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD-check.cmake8
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD.cmake2
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check-common.cmake12
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-common.cmake42
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.h0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.c0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.h0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/empty2.h0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/empty3.h0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/main.c4
32 files changed, 431 insertions, 167 deletions
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index 38fa6f9..31f0573 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -1282,7 +1282,7 @@ Compile Context
.. versionadded:: 3.27
Content of ``...``, when collecting
- :ref:`usage requirements <Target Usage Requirements>`,
+ :ref:`transitive build properties <Transitive Build Properties>`,
otherwise it is the empty string. This is intended for use in an
:prop_tgt:`INTERFACE_LINK_LIBRARIES` and :prop_tgt:`LINK_LIBRARIES` target
properties, typically populated via the :command:`target_link_libraries` command.
@@ -1670,8 +1670,8 @@ Link Context
.. versionadded:: 3.1
- Content of ``...``, except while collecting
- :ref:`usage requirements <Target Usage Requirements>`,
+ Content of ``...``, except while collecting usage requirements from
+ :ref:`transitive build properties <Transitive Build Properties>`,
in which case it is the empty string. This is intended for use in an
:prop_tgt:`INTERFACE_LINK_LIBRARIES` target property, typically populated
via the :command:`target_link_libraries` command, to specify private link
@@ -1788,7 +1788,16 @@ The expressions have special evaluation rules for some properties:
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`.
Evaluation is transitive over the closure of the target's
- :prop_tgt:`INTERFACE_LINK_LIBRARIES`.
+ :prop_tgt:`INTERFACE_LINK_LIBRARIES`:
+
+ * For :ref:`Transitive Build Properties`, the transitive closure
+ *excludes* entries of :prop_tgt:`INTERFACE_LINK_LIBRARIES` guarded
+ by the :genex:`LINK_ONLY` generator expression.
+
+ * For :ref:`Transitive Link Properties`, the transitive closure is
+ *includes* entries of :prop_tgt:`INTERFACE_LINK_LIBRARIES` guarded
+ by the :genex:`LINK_ONLY` generator expression.
+ See policy :policy:`CMP0166`.
Evaluation of :prop_tgt:`INTERFACE_LINK_LIBRARIES` itself is not transitive.
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index e46e88e..826790d 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.30
.. toctree::
:maxdepth: 1
+ CMP0166: TARGET_PROPERTY evaluates link properties transitively over private dependencies of static libraries. </policy/CMP0166>
CMP0165: enable_language() must not be called before project(). </policy/CMP0165>
CMP0164: add_library() rejects SHARED libraries when not supported by the platform. </policy/CMP0164>
CMP0163: The GENERATED source file property is now visible in all directories. </policy/CMP0163>
@@ -214,7 +215,7 @@ Policies Introduced by CMake 3.17
CMP0102: mark_as_advanced() does nothing if a cache entry does not exist. </policy/CMP0102>
CMP0101: target_compile_options honors BEFORE keyword in all scopes. </policy/CMP0101>
CMP0100: Let AUTOMOC and AUTOUIC process .hh header files. </policy/CMP0100>
- CMP0099: Link properties are transitive over private dependency on static libraries. </policy/CMP0099>
+ CMP0099: Link properties are transitive over private dependencies of static libraries. </policy/CMP0099>
CMP0098: FindFLEX runs flex in CMAKE_CURRENT_BINARY_DIR when executing. </policy/CMP0098>
Policies Introduced by CMake 3.16
diff --git a/Help/policy/CMP0099.rst b/Help/policy/CMP0099.rst
index c0db99d..0a2b786 100644
--- a/Help/policy/CMP0099.rst
+++ b/Help/policy/CMP0099.rst
@@ -3,13 +3,16 @@ CMP0099
.. versionadded:: 3.17
-Target link properties :prop_tgt:`INTERFACE_LINK_OPTIONS`,
-:prop_tgt:`INTERFACE_LINK_DIRECTORIES` and :prop_tgt:`INTERFACE_LINK_DEPENDS`
-are now transitive over private dependencies of static libraries.
+Link properties are transitive over private dependencies of static libraries.
-In CMake 3.16 and below the interface link properties attached to libraries
-are not propagated for private dependencies of static libraries.
+In CMake 3.16 and below, evaluation of target properties
+:prop_tgt:`INTERFACE_LINK_OPTIONS`, :prop_tgt:`INTERFACE_LINK_DIRECTORIES`,
+and :prop_tgt:`INTERFACE_LINK_DEPENDS` during buildsystem generation does not
+follow private dependencies of static libraries, which appear in their
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` guarded by :genex:`LINK_ONLY` generator
+expressions.
Only the libraries themselves are propagated to link the dependent binary.
+
CMake 3.17 and later prefer to propagate all interface link properties.
This policy provides compatibility for projects that have not been updated
to expect the new behavior.
@@ -18,6 +21,12 @@ The ``OLD`` behavior for this policy is to not propagate interface link
properties. The ``NEW`` behavior of this policy is to propagate interface link
properties.
+.. versionadded:: 3.30
+
+ Policy :policy:`CMP0166` makes :genex:`TARGET_PROPERTY` evaluation of
+ these three transitive link properties follow private dependencies of
+ static libraries too.
+
.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 3.17
.. |WARNS_OR_DOES_NOT_WARN| replace:: does *not* warn
.. include:: STANDARD_ADVICE.txt
diff --git a/Help/policy/CMP0166.rst b/Help/policy/CMP0166.rst
new file mode 100644
index 0000000..5c67880
--- /dev/null
+++ b/Help/policy/CMP0166.rst
@@ -0,0 +1,40 @@
+CMP0166
+-------
+
+.. versionadded:: 3.30
+
+:genex:`TARGET_PROPERTY` evaluates link properties transitively over private
+dependencies of static libraries.
+
+In CMake 3.29 and below, the :genex:`TARGET_PROPERTY` generator expression
+evaluates properties :prop_tgt:`INTERFACE_LINK_OPTIONS`,
+:prop_tgt:`INTERFACE_LINK_DIRECTORIES`, and :prop_tgt:`INTERFACE_LINK_DEPENDS`
+as if they were :ref:`Transitive Build Properties` rather than
+:ref:`Transitive Link Properties`, even when policy :policy:`CMP0099` is
+set to ``NEW``. Private dependencies of static libraries, which appear in
+their :prop_tgt:`INTERFACE_LINK_LIBRARIES` guarded by :genex:`LINK_ONLY`
+generator expressions, are not followed. This is inconsistent with
+evaluation of the same target properties during buildsystem generation.
+
+CMake 3.30 and above prefer that :genex:`TARGET_PROPERTY` evaluates
+properties :prop_tgt:`INTERFACE_LINK_OPTIONS`,
+:prop_tgt:`INTERFACE_LINK_DIRECTORIES`, and :prop_tgt:`INTERFACE_LINK_DEPENDS`
+as :ref:`Transitive Link Properties` such that private dependencies of static
+libraries, which appear in their :prop_tgt:`INTERFACE_LINK_LIBRARIES` guarded
+by :genex:`LINK_ONLY` generator expressions, are followed.
+This policy provides compatibility for projects that have not been updated
+to expect the new behavior.
+
+The ``OLD`` behavior for this policy is for :genex:`TARGET_PROPERTY` to
+evaluate properties :prop_tgt:`INTERFACE_LINK_OPTIONS`,
+:prop_tgt:`INTERFACE_LINK_DIRECTORIES`, and :prop_tgt:`INTERFACE_LINK_DEPENDS`
+as if they were :ref:`Transitive Build Properties` by not following private
+dependencies of static libraries. The ``NEW`` behavior for this policy is
+to evaluate them as :ref:`Transitive Link Properties` by following private
+dependencies of static libraries.
+
+.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 3.30
+.. |WARNS_OR_DOES_NOT_WARN| replace:: does *not* warn
+.. include:: STANDARD_ADVICE.txt
+
+.. include:: DEPRECATED.txt
diff --git a/Help/release/dev/genex-link-properties.rst b/Help/release/dev/genex-link-properties.rst
new file mode 100644
index 0000000..e1e84e0
--- /dev/null
+++ b/Help/release/dev/genex-link-properties.rst
@@ -0,0 +1,8 @@
+genex-link-properties
+---------------------
+
+* The :genex:`TARGET_PROPERTY` generator expression now evaluates target
+ properties :prop_tgt:`INTERFACE_LINK_OPTIONS`,
+ :prop_tgt:`INTERFACE_LINK_DIRECTORIES`, and
+ :prop_tgt:`INTERFACE_LINK_DEPENDS` correctly by following private
+ dependencies of static libraries. See policy :policy:`CMP0166`.
diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx
index 677bb48..fbf39e2 100644
--- a/Source/cmCommonTargetGenerator.cxx
+++ b/Source/cmCommonTargetGenerator.cxx
@@ -501,7 +501,8 @@ std::string cmCommonTargetGenerator::GetLinkerLauncher(
cmValue launcherProp = this->GeneratorTarget->GetProperty(propName);
if (cmNonempty(launcherProp)) {
cmGeneratorExpressionDAGChecker dagChecker(this->GeneratorTarget, propName,
- nullptr, nullptr);
+ nullptr, nullptr,
+ this->LocalCommonGenerator);
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 f4b26f3..f6ff71a 100644
--- a/Source/cmComputeLinkDepends.cxx
+++ b/Source/cmComputeLinkDepends.cxx
@@ -451,10 +451,14 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target,
if (cmValue feature = this->Target->GetProperty(key)) {
if (!feature->empty() && key.length() > lloPrefix.length()) {
auto item = key.substr(lloPrefix.length());
- cmGeneratorExpressionDAGChecker dag{ this->Target->GetBacktrace(),
- this->Target,
- "LINK_LIBRARY_OVERRIDE",
- nullptr, nullptr };
+ cmGeneratorExpressionDAGChecker dag{
+ this->Target->GetBacktrace(),
+ this->Target,
+ "LINK_LIBRARY_OVERRIDE",
+ nullptr,
+ nullptr,
+ this->Target->GetLocalGenerator()
+ };
auto overrideFeature = cmGeneratorExpression::Evaluate(
*feature, this->Target->GetLocalGenerator(), config,
this->Target, &dag, this->Target, linkLanguage);
@@ -466,9 +470,12 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target,
// global override property
if (cmValue linkLibraryOverride =
this->Target->GetProperty("LINK_LIBRARY_OVERRIDE")) {
- cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
- "LINK_LIBRARY_OVERRIDE", nullptr,
- nullptr };
+ cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(),
+ target,
+ "LINK_LIBRARY_OVERRIDE",
+ nullptr,
+ nullptr,
+ target->GetLocalGenerator() };
auto overrideValue = cmGeneratorExpression::Evaluate(
*linkLibraryOverride, target->GetLocalGenerator(), config, target, &dag,
target, linkLanguage);
diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx
index 00c9173..4c41ff5 100644
--- a/Source/cmExportTryCompileFileGenerator.cxx
+++ b/Source/cmExportTryCompileFileGenerator.cxx
@@ -2,9 +2,11 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmExportTryCompileFileGenerator.h"
+#include <map>
#include <utility>
#include <cm/memory>
+#include <cm/string_view>
#include "cmFileSet.h"
#include "cmGeneratorExpression.h"
@@ -44,12 +46,10 @@ bool cmExportTryCompileFileGenerator::GenerateMainFile(std::ostream& os)
ImportPropertyMap properties;
for (std::string const& lang : this->Languages) {
-#define FIND_TARGETS(PROPERTY) \
- this->FindTargets("INTERFACE_" #PROPERTY, te, lang, emittedDeps);
-
- CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(FIND_TARGETS)
-
-#undef FIND_TARGETS
+ for (auto i : cmGeneratorTarget::BuiltinTransitiveProperties) {
+ this->FindTargets(std::string(i.second.InterfaceName), te, lang,
+ emittedDeps);
+ }
}
this->PopulateProperties(te, properties, emittedDeps);
@@ -76,10 +76,10 @@ 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, "LINK_OPTIONS", nullptr, nullptr, tgt->GetLocalGenerator());
}
- cmGeneratorExpressionDAGChecker dagChecker(tgt, propName, nullptr,
- parentDagChecker.get());
+ cmGeneratorExpressionDAGChecker dagChecker(
+ tgt, propName, nullptr, parentDagChecker.get(), tgt->GetLocalGenerator());
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*prop);
diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx
index 0b96c3f..0583fd5 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);
+ nullptr, this->LocalGenerator);
return this->CompiledGeneratorExpression->Evaluate(
this->LocalGenerator, this->Config, this->HeadTarget, &dagChecker, nullptr,
diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx
index fda7ec3..bb1f4b4 100644
--- a/Source/cmGeneratorExpressionDAGChecker.cxx
+++ b/Source/cmGeneratorExpressionDAGChecker.cxx
@@ -2,10 +2,10 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmGeneratorExpressionDAGChecker.h"
-#include <cstring>
#include <sstream>
#include <utility>
+#include <cm/optional>
#include <cm/string_view>
#include <cmext/string_view>
@@ -20,16 +20,17 @@
cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
cmGeneratorTarget const* target, std::string property,
const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* parent)
+ cmGeneratorExpressionDAGChecker* parent, cmLocalGenerator const* contextLG)
: cmGeneratorExpressionDAGChecker(cmListFileBacktrace(), target,
- std::move(property), content, parent)
+ std::move(property), content, parent,
+ contextLG)
{
}
cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
cmListFileBacktrace backtrace, cmGeneratorTarget const* target,
std::string property, const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* parent)
+ cmGeneratorExpressionDAGChecker* parent, cmLocalGenerator const* contextLG)
: Parent(parent)
, Top(parent ? parent->Top : this)
, Target(target)
@@ -40,10 +41,9 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
if (parent) {
this->TopIsTransitiveProperty = parent->TopIsTransitiveProperty;
} else {
-#define TEST_TRANSITIVE_PROPERTY_METHOD(METHOD) this->METHOD() ||
- this->TopIsTransitiveProperty = (CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
- TEST_TRANSITIVE_PROPERTY_METHOD) false); // NOLINT(*)
-#undef TEST_TRANSITIVE_PROPERTY_METHOD
+ this->TopIsTransitiveProperty =
+ this->Target->IsTransitiveProperty(this->Property, contextLG)
+ .has_value();
}
this->CheckResult = this->CheckGraph();
@@ -169,6 +169,12 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingCompileExpression() const
property == "COMPILE_DEFINITIONS"_s || property == "COMPILE_OPTIONS"_s;
}
+bool cmGeneratorExpressionDAGChecker::EvaluatingSources() const
+{
+ return this->Property == "SOURCES"_s ||
+ this->Property == "INTERFACE_SOURCES"_s;
+}
+
bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const
{
cm::string_view property(this->Top->Property);
@@ -222,39 +228,3 @@ cmGeneratorTarget const* cmGeneratorExpressionDAGChecker::TopTarget() const
{
return this->Top->Target;
}
-
-enum class TransitiveProperty
-{
-#define DEFINE_ENUM_ENTRY(NAME) NAME,
- CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(DEFINE_ENUM_ENTRY)
-#undef DEFINE_ENUM_ENTRY
- Terminal
-};
-
-template <TransitiveProperty>
-bool additionalTest(const char* const /*unused*/)
-{
- return false;
-}
-
-template <>
-bool additionalTest<TransitiveProperty::COMPILE_DEFINITIONS>(
- const char* const prop)
-{
- return cmHasLiteralPrefix(prop, "COMPILE_DEFINITIONS_");
-}
-
-#define DEFINE_TRANSITIVE_PROPERTY_METHOD(METHOD, PROPERTY) \
- bool cmGeneratorExpressionDAGChecker::METHOD() const \
- { \
- const char* const prop = this->Property.c_str(); \
- if (strcmp(prop, #PROPERTY) == 0 || \
- strcmp(prop, "INTERFACE_" #PROPERTY) == 0) { \
- return true; \
- } \
- return additionalTest<TransitiveProperty::PROPERTY>(prop); \
- }
-
-CM_FOR_EACH_TRANSITIVE_PROPERTY(DEFINE_TRANSITIVE_PROPERTY_METHOD)
-
-#undef DEFINE_TRANSITIVE_PROPERTY_METHOD
diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h
index 068ba6b..b230188 100644
--- a/Source/cmGeneratorExpressionDAGChecker.h
+++ b/Source/cmGeneratorExpressionDAGChecker.h
@@ -13,33 +13,7 @@
struct GeneratorExpressionContent;
struct cmGeneratorExpressionContext;
class cmGeneratorTarget;
-
-#define CM_SELECT_BOTH(F, A1, A2) F(A1, A2)
-#define CM_SELECT_FIRST(F, A1, A2) F(A1)
-#define CM_SELECT_SECOND(F, A1, A2) F(A2)
-
-#define CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, SELECT) \
- SELECT(F, EvaluatingIncludeDirectories, INCLUDE_DIRECTORIES) \
- SELECT(F, EvaluatingSystemIncludeDirectories, SYSTEM_INCLUDE_DIRECTORIES) \
- SELECT(F, EvaluatingCompileDefinitions, COMPILE_DEFINITIONS) \
- SELECT(F, EvaluatingCompileOptions, COMPILE_OPTIONS) \
- SELECT(F, EvaluatingAutoMocMacroNames, AUTOMOC_MACRO_NAMES) \
- SELECT(F, EvaluatingAutoUicOptions, AUTOUIC_OPTIONS) \
- SELECT(F, EvaluatingSources, SOURCES) \
- SELECT(F, EvaluatingCompileFeatures, COMPILE_FEATURES) \
- SELECT(F, EvaluatingLinkOptions, LINK_OPTIONS) \
- SELECT(F, EvaluatingLinkDirectories, LINK_DIRECTORIES) \
- SELECT(F, EvaluatingLinkDepends, LINK_DEPENDS) \
- SELECT(F, EvaluatingPrecompileHeaders, PRECOMPILE_HEADERS)
-
-#define CM_FOR_EACH_TRANSITIVE_PROPERTY(F) \
- CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_BOTH)
-
-#define CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(F) \
- CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_FIRST)
-
-#define CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(F) \
- CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_SECOND)
+class cmLocalGenerator;
struct cmGeneratorExpressionDAGChecker
{
@@ -47,11 +21,13 @@ struct cmGeneratorExpressionDAGChecker
cmGeneratorTarget const* target,
std::string property,
const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* parent);
+ cmGeneratorExpressionDAGChecker* parent,
+ cmLocalGenerator const* contextLG);
cmGeneratorExpressionDAGChecker(cmGeneratorTarget const* target,
std::string property,
const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* parent);
+ cmGeneratorExpressionDAGChecker* parent,
+ cmLocalGenerator const* contextLG);
enum Result
{
@@ -83,11 +59,7 @@ struct cmGeneratorExpressionDAGChecker
bool EvaluatingLinkLibraries(cmGeneratorTarget const* tgt = nullptr,
ForGenex genex = ForGenex::ANY) const;
-#define DECLARE_TRANSITIVE_PROPERTY_METHOD(METHOD) bool METHOD() const;
-
- CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(DECLARE_TRANSITIVE_PROPERTY_METHOD)
-
-#undef DECLARE_TRANSITIVE_PROPERTY_METHOD
+ bool EvaluatingSources() const;
bool GetTransitivePropertiesOnly() const;
void SetTransitivePropertiesOnly() { this->TransitivePropertiesOnly = true; }
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 0df086b..b9feb87 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -487,7 +487,8 @@ protected:
if (context->HeadTarget) {
cmGeneratorExpressionDAGChecker dagChecker(
context->Backtrace, context->HeadTarget,
- genexOperator + ":" + expression, content, dagCheckerParent);
+ genexOperator + ":" + expression, content, dagCheckerParent,
+ context->LG);
switch (dagChecker.Check()) {
case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: {
@@ -2700,7 +2701,8 @@ static const struct DeviceLinkNode : public cmGeneratorExpressionNode
static std::string getLinkedTargetsContent(
cmGeneratorTarget const* target, std::string const& prop,
cmGeneratorExpressionContext* context,
- cmGeneratorExpressionDAGChecker* dagChecker)
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ cmGeneratorTarget::LinkInterfaceFor interfaceFor)
{
std::string result;
if (cmLinkImplementationLibraries const* impl =
@@ -2716,8 +2718,7 @@ static std::string getLinkedTargetsContent(
target, context->EvaluateForBuildsystem, lib.Backtrace,
context->Language);
std::string libResult = lib.Target->EvaluateInterfaceProperty(
- prop, &libContext, dagChecker,
- cmGeneratorTarget::LinkInterfaceFor::Usage);
+ prop, &libContext, dagChecker, interfaceFor);
if (!libResult.empty()) {
if (result.empty()) {
result = std::move(libResult);
@@ -2875,25 +2876,15 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
std::string interfacePropertyName;
bool isInterfaceProperty = false;
+ cmGeneratorTarget::LinkInterfaceFor interfaceFor =
+ cmGeneratorTarget::LinkInterfaceFor::Usage;
-#define POPULATE_INTERFACE_PROPERTY_NAME(prop) \
- if (propertyName == #prop) { \
- interfacePropertyName = "INTERFACE_" #prop; \
- } else if (propertyName == "INTERFACE_" #prop) { \
- interfacePropertyName = "INTERFACE_" #prop; \
- isInterfaceProperty = true; \
- } else
-
- CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(POPULATE_INTERFACE_PROPERTY_NAME)
- // Note that the above macro terminates with an else
- /* else */ if (cmHasLiteralPrefix(propertyName, "COMPILE_DEFINITIONS_")) {
- cmPolicies::PolicyStatus polSt =
- context->LG->GetPolicyStatus(cmPolicies::CMP0043);
- if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
- interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS";
- }
+ if (cm::optional<cmGeneratorTarget::TransitiveProperty> transitiveProp =
+ target->IsTransitiveProperty(propertyName, context->LG)) {
+ interfacePropertyName = std::string(transitiveProp->InterfaceName);
+ isInterfaceProperty = transitiveProp->InterfaceName == propertyName;
+ interfaceFor = transitiveProp->InterfaceFor;
}
-#undef POPULATE_INTERFACE_PROPERTY_NAME
bool evaluatingLinkLibraries = false;
@@ -2916,20 +2907,19 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
return std::string();
}
} else {
- assert(dagCheckerParent
- ->EvaluatingTransitiveProperty()); // NOLINT(clang-tidy)
+ assert(dagCheckerParent->EvaluatingTransitiveProperty());
}
}
if (isInterfaceProperty) {
return cmGeneratorExpression::StripEmptyListElements(
- target->EvaluateInterfaceProperty(
- propertyName, context, dagCheckerParent,
- cmGeneratorTarget::LinkInterfaceFor::Usage));
+ target->EvaluateInterfaceProperty(propertyName, context,
+ dagCheckerParent, interfaceFor));
}
- cmGeneratorExpressionDAGChecker dagChecker(
- context->Backtrace, target, propertyName, content, dagCheckerParent);
+ cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, target,
+ propertyName, content,
+ dagCheckerParent, context->LG);
switch (dagChecker.Check()) {
case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
@@ -3011,7 +3001,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
this->EvaluateDependentExpression(result, context->LG, context, target,
&dagChecker, target));
std::string linkedTargetsContent = getLinkedTargetsContent(
- target, interfacePropertyName, context, &dagChecker);
+ target, interfacePropertyName, context, &dagChecker, interfaceFor);
if (!linkedTargetsContent.empty()) {
result += (result.empty() ? "" : ";") + linkedTargetsContent;
}
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 319526a..c14ff3a 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -65,6 +65,7 @@
namespace {
using LinkInterfaceFor = cmGeneratorTarget::LinkInterfaceFor;
+using TransitiveProperty = cmGeneratorTarget::TransitiveProperty;
const std::string kINTERFACE_LINK_LIBRARIES = "INTERFACE_LINK_LIBRARIES";
const std::string kINTERFACE_LINK_LIBRARIES_DIRECT =
@@ -73,6 +74,33 @@ const std::string kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE =
"INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE";
}
+const std::map<cm::string_view, TransitiveProperty>
+ cmGeneratorTarget::BuiltinTransitiveProperties = {
+ { "AUTOMOC_MACRO_NAMES"_s,
+ { "INTERFACE_AUTOMOC_MACRO_NAMES"_s, LinkInterfaceFor::Usage } },
+ { "AUTOUIC_OPTIONS"_s,
+ { "INTERFACE_AUTOUIC_OPTIONS"_s, LinkInterfaceFor::Usage } },
+ { "COMPILE_DEFINITIONS"_s,
+ { "INTERFACE_COMPILE_DEFINITIONS"_s, LinkInterfaceFor::Usage } },
+ { "COMPILE_FEATURES"_s,
+ { "INTERFACE_COMPILE_FEATURES"_s, LinkInterfaceFor::Usage } },
+ { "COMPILE_OPTIONS"_s,
+ { "INTERFACE_COMPILE_OPTIONS"_s, LinkInterfaceFor::Usage } },
+ { "INCLUDE_DIRECTORIES"_s,
+ { "INTERFACE_INCLUDE_DIRECTORIES"_s, LinkInterfaceFor::Usage } },
+ { "LINK_DEPENDS"_s,
+ { "INTERFACE_LINK_DEPENDS"_s, LinkInterfaceFor::Link } },
+ { "LINK_DIRECTORIES"_s,
+ { "INTERFACE_LINK_DIRECTORIES"_s, LinkInterfaceFor::Link } },
+ { "LINK_OPTIONS"_s,
+ { "INTERFACE_LINK_OPTIONS"_s, LinkInterfaceFor::Link } },
+ { "PRECOMPILE_HEADERS"_s,
+ { "INTERFACE_PRECOMPILE_HEADERS"_s, LinkInterfaceFor::Usage } },
+ { "SOURCES"_s, { "INTERFACE_SOURCES"_s, LinkInterfaceFor::Usage } },
+ { "SYSTEM_INCLUDE_DIRECTORIES"_s,
+ { "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES"_s, LinkInterfaceFor::Usage } },
+ };
+
template <>
cmValue cmTargetPropertyComputer::GetSources<cmGeneratorTarget>(
cmGeneratorTarget const* tgt, cmMakefile const& /* mf */)
@@ -887,7 +915,7 @@ std::string cmGeneratorTarget::GetLinkerTypeProperty(
auto linkerType = this->GetProperty(propName);
if (!linkerType.IsEmpty()) {
cmGeneratorExpressionDAGChecker dagChecker(this, propName, nullptr,
- nullptr);
+ nullptr, this->LocalGenerator);
auto ltype =
cmGeneratorExpression::Evaluate(*linkerType, this->GetLocalGenerator(),
config, this, &dagChecker, this, lang);
@@ -1352,7 +1380,8 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory(
if (iter == this->SystemIncludesCache.end()) {
cmGeneratorExpressionDAGChecker dagChecker(
- this, "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr);
+ this, "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr,
+ this->LocalGenerator);
bool excludeImported = this->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED");
@@ -1460,7 +1489,8 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty(
// a subset of TargetPropertyNode::Evaluate without stringify/parse steps
// but sufficient for transitive interface properties.
cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, this, prop,
- nullptr, dagCheckerParent);
+ nullptr, dagCheckerParent,
+ this->LocalGenerator);
switch (dagChecker.Check()) {
case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
dagChecker.ReportError(
@@ -1525,6 +1555,38 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty(
return result;
}
+cm::optional<cmGeneratorTarget::TransitiveProperty>
+cmGeneratorTarget::IsTransitiveProperty(cm::string_view prop,
+ cmLocalGenerator const* lg) const
+{
+ cm::optional<TransitiveProperty> result;
+ static const cm::string_view kINTERFACE_ = "INTERFACE_"_s;
+ if (cmHasPrefix(prop, kINTERFACE_)) {
+ prop = prop.substr(kINTERFACE_.length());
+ }
+ auto i = BuiltinTransitiveProperties.find(prop);
+ if (i != BuiltinTransitiveProperties.end()) {
+ result = i->second;
+ if (result->InterfaceFor != cmGeneratorTarget::LinkInterfaceFor::Usage) {
+ cmPolicies::PolicyStatus cmp0166 =
+ lg->GetPolicyStatus(cmPolicies::CMP0166);
+ if ((cmp0166 == cmPolicies::WARN || cmp0166 == cmPolicies::OLD) &&
+ (prop == "LINK_DIRECTORIES"_s || prop == "LINK_DEPENDS"_s ||
+ prop == "LINK_OPTIONS"_s)) {
+ result->InterfaceFor = cmGeneratorTarget::LinkInterfaceFor::Usage;
+ }
+ }
+ } else if (cmHasLiteralPrefix(prop, "COMPILE_DEFINITIONS_")) {
+ cmPolicies::PolicyStatus cmp0043 =
+ lg->GetPolicyStatus(cmPolicies::CMP0043);
+ if (cmp0043 == cmPolicies::WARN || cmp0043 == cmPolicies::OLD) {
+ result = TransitiveProperty{ "INTERFACE_COMPILE_DEFINITIONS"_s,
+ LinkInterfaceFor::Usage };
+ }
+ }
+ return result;
+}
+
namespace {
enum class IncludeDirectoryFallBack
@@ -1539,8 +1601,10 @@ std::string AddLangSpecificInterfaceIncludeDirectories(
const std::string& propertyName, IncludeDirectoryFallBack mode,
cmGeneratorExpressionDAGChecker* context)
{
- cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
- propertyName, nullptr, context };
+ cmGeneratorExpressionDAGChecker dag{
+ target->GetBacktrace(), target, propertyName, nullptr, context,
+ target->GetLocalGenerator()
+ };
switch (dag.Check()) {
case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
dag.ReportError(
@@ -1590,8 +1654,10 @@ void AddLangSpecificImplicitIncludeDirectories(
{
if (const auto* libraries = target->GetLinkImplementationLibraries(
config, LinkInterfaceFor::Usage)) {
- cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
- propertyName, nullptr, nullptr };
+ cmGeneratorExpressionDAGChecker dag{
+ target->GetBacktrace(), target, propertyName, nullptr, nullptr,
+ target->GetLocalGenerator()
+ };
for (const cmLinkImplItem& library : libraries->Libraries) {
if (const cmGeneratorTarget* dependency = library.Target) {
@@ -1843,8 +1909,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths(
this->DebugSourcesDone = true;
}
- cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr,
- nullptr);
+ cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr, nullptr,
+ this->LocalGenerator);
EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
this, config, std::string(), &dagChecker, this->SourceEntries);
@@ -3058,7 +3124,7 @@ void cmGeneratorTarget::GetAutoUicOptions(std::vector<std::string>& result,
}
cmGeneratorExpressionDAGChecker dagChecker(this, "AUTOUIC_OPTIONS", nullptr,
- nullptr);
+ nullptr, this->LocalGenerator);
cmExpandList(cmGeneratorExpression::Evaluate(prop, this->LocalGenerator,
config, this, &dagChecker),
result);
@@ -3858,8 +3924,8 @@ 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);
+ cmGeneratorExpressionDAGChecker dagChecker(
+ this, "INCLUDE_DIRECTORIES", nullptr, nullptr, this->LocalGenerator);
cmList debugProperties{ this->Makefile->GetDefinition(
"CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -4123,7 +4189,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions(
std::unordered_set<std::string> uniqueOptions;
cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_OPTIONS", nullptr,
- nullptr);
+ nullptr, this->LocalGenerator);
cmList debugProperties{ this->Makefile->GetDefinition(
"CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -4164,7 +4230,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileFeatures(
std::unordered_set<std::string> uniqueFeatures;
cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_FEATURES", nullptr,
- nullptr);
+ nullptr, this->LocalGenerator);
cmList debugProperties{ this->Makefile->GetDefinition(
"CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -4213,8 +4279,8 @@ 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);
+ cmGeneratorExpressionDAGChecker dagChecker(
+ this, "COMPILE_DEFINITIONS", nullptr, nullptr, this->LocalGenerator);
cmList debugProperties{ this->Makefile->GetDefinition(
"CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -4277,8 +4343,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders(
}
std::unordered_set<std::string> uniqueOptions;
- cmGeneratorExpressionDAGChecker dagChecker(this, "PRECOMPILE_HEADERS",
- nullptr, nullptr);
+ cmGeneratorExpressionDAGChecker dagChecker(
+ this, "PRECOMPILE_HEADERS", nullptr, nullptr, this->LocalGenerator);
cmList debugProperties{ this->Makefile->GetDefinition(
"CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -4667,7 +4733,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions(
std::unordered_set<std::string> uniqueOptions;
cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_OPTIONS", nullptr,
- nullptr);
+ nullptr, this->LocalGenerator);
cmList debugProperties{ this->Makefile->GetDefinition(
"CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -4835,8 +4901,8 @@ 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);
+ cmGeneratorExpressionDAGChecker dagChecker(
+ this, "STATIC_LIBRARY_OPTIONS", nullptr, nullptr, this->LocalGenerator);
EvaluatedTargetPropertyEntries entries;
if (cmValue linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) {
@@ -4949,7 +5015,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories(
std::unordered_set<std::string> uniqueDirectories;
cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DIRECTORIES", nullptr,
- nullptr);
+ nullptr, this->LocalGenerator);
cmList debugProperties{ this->Makefile->GetDefinition(
"CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -4993,7 +5059,7 @@ 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);
+ nullptr, this->LocalGenerator);
EvaluatedTargetPropertyEntries entries;
if (cmValue linkDepends = this->GetProperty("LINK_DEPENDS")) {
@@ -6979,7 +7045,8 @@ void cmGeneratorTarget::ExpandLinkItems(
return;
}
// Keep this logic in sync with ComputeLinkImplementationLibraries.
- cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr);
+ cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr,
+ this->LocalGenerator);
// The $<LINK_ONLY> expression may be in a link interface to specify
// private link dependencies that are otherwise excluded from usage
// requirements.
@@ -8654,7 +8721,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
for (auto const& entry : entryRange) {
// Keep this logic in sync with ExpandLinkItems.
cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_LIBRARIES", nullptr,
- nullptr);
+ nullptr, this->LocalGenerator);
// The $<LINK_ONLY> expression may be used to specify link dependencies
// that are otherwise excluded from usage requirements.
if (implFor == LinkInterfaceFor::Usage) {
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 6228daf..678656a 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -15,6 +15,7 @@
#include <vector>
#include <cm/optional>
+#include <cm/string_view>
#include "cmAlgorithms.h"
#include "cmComputeLinkInformation.h"
@@ -886,6 +887,18 @@ public:
cmGeneratorExpressionDAGChecker* dagCheckerParent,
LinkInterfaceFor interfaceFor) const;
+ struct TransitiveProperty
+ {
+ cm::string_view InterfaceName;
+ LinkInterfaceFor InterfaceFor;
+ };
+
+ static const std::map<cm::string_view, TransitiveProperty>
+ BuiltinTransitiveProperties;
+
+ cm::optional<TransitiveProperty> IsTransitiveProperty(
+ cm::string_view prop, cmLocalGenerator const* lg) const;
+
bool HaveInstallTreeRPATH(const std::string& config) const;
bool GetBuildRPATH(const std::string& config, std::string& rpath) const;
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index ada87dd..eb9f031 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -294,8 +294,8 @@ class cmMakefile;
"FindFLEX runs flex in CMAKE_CURRENT_BINARY_DIR when executing.", 3, \
17, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0099, \
- "Link properties are transitive over private dependency on static " \
- "libraries.", \
+ "Link properties are transitive over private dependencies of " \
+ "static libraries.", \
3, 17, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0100, "Let AUTOMOC and AUTOUIC process .hh files.", 3, \
17, 0, cmPolicies::WARN) \
@@ -508,7 +508,11 @@ class cmMakefile;
3, 30, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0165, \
"enable_language() must not be called before project().", 3, 30, 0, \
- cmPolicies::WARN)
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0166, \
+ "TARGET_PROPERTY evaluates link properties transitively over " \
+ "private dependencies of static libraries.", \
+ 3, 30, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 0ccebfd..34a47cc 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -1918,8 +1918,9 @@ 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);
+ cmGeneratorExpressionDAGChecker dagChecker(this->GenTarget,
+ "AUTOMOC_MACRO_NAMES", nullptr,
+ nullptr, this->LocalGen);
EvaluatedTargetPropertyEntries InterfaceAutoMocMacroNamesEntries;
if (this->MultiConfig) {
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt
index 32d92d8..5791993 100644
--- a/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt
@@ -1,6 +1,6 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.17)
if(RunCMake_TEST STREQUAL "LOCATION")
cmake_minimum_required(VERSION 2.8.12) # Leave CMP0026 unset.
endif()
project(${RunCMake_TEST} NONE)
-include(${RunCMake_TEST}.cmake)
+include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE)
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake
index b613ad1..07052eb 100644
--- a/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake
@@ -13,6 +13,9 @@ run_cmake(LinkImplementationCycle5)
run_cmake(LinkImplementationCycle6)
run_cmake(LOCATION)
run_cmake(SOURCES)
+run_cmake(TransitiveBuild)
+run_cmake(TransitiveLink-CMP0166-OLD)
+run_cmake(TransitiveLink-CMP0166-NEW)
block()
run_cmake(Scope)
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild-check.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild-check.cmake
new file mode 100644
index 0000000..65adfaf
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild-check.cmake
@@ -0,0 +1,25 @@
+set(expect [[
+# file\(GENERATE\) produced:
+main INCLUDE_DIRECTORIES: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dirM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dir1'
+main SYSTEM_INCLUDE_DIRECTORIES: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/sys1'
+main COMPILE_DEFINITIONS: 'DEFM;DEF1'
+main COMPILE_FEATURES: 'cxx_std_20;cxx_std_11'
+main COMPILE_OPTIONS: '-optM;-opt1'
+main PRECOMPILE_HEADERS: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.h;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.h'
+main SOURCES: 'main.c;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.c'
+main AUTOMOC_MACRO_NAMES: 'MOCM;MOC1'
+main AUTOUIC_OPTIONS: '-uicM;-uic1'
+]])
+
+string(REGEX REPLACE "\r\n" "\n" expect "${expect}")
+string(REGEX REPLACE "\n+$" "" expect "${expect}")
+
+file(READ "${RunCMake_TEST_BINARY_DIR}/out.txt" 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/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild.cmake
new file mode 100644
index 0000000..8f8eb96
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild.cmake
@@ -0,0 +1,66 @@
+enable_language(C)
+set(CMAKE_PCH_EXTENSION "") # suppress cmake_pch from SOURCES
+
+add_library(foo1 STATIC empty.c)
+target_link_libraries(foo1 PRIVATE foo2 foo3)
+target_include_directories(foo1 INTERFACE dir1)
+target_compile_definitions(foo1 INTERFACE DEF1)
+target_compile_features(foo1 INTERFACE cxx_std_11)
+target_compile_options(foo1 INTERFACE -opt1)
+target_precompile_headers(foo1 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/empty1.h")
+target_sources(foo1 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/empty1.c")
+set_target_properties(foo1 PROPERTIES
+ INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/sys1"
+ INTERFACE_AUTOMOC_MACRO_NAMES "MOC1"
+ INTERFACE_AUTOUIC_OPTIONS "-uic1"
+ )
+
+add_library(foo2 STATIC empty.c)
+target_include_directories(foo2 INTERFACE dir2)
+target_compile_definitions(foo2 INTERFACE DEF2)
+target_compile_features(foo2 INTERFACE cxx_std_14)
+target_compile_options(foo2 INTERFACE -opt2)
+target_precompile_headers(foo2 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/empty2.h")
+target_sources(foo2 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/empty2.c")
+set_target_properties(foo2 PROPERTIES
+ INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/sys2"
+ INTERFACE_AUTOMOC_MACRO_NAMES "MOC2"
+ INTERFACE_AUTOUIC_OPTIONS "-uic2"
+ )
+
+add_library(foo3 STATIC empty.c)
+target_include_directories(foo3 PRIVATE dir3)
+target_compile_definitions(foo3 PRIVATE DEF3)
+target_compile_features(foo3 PRIVATE cxx_std_17)
+target_compile_options(foo3 PRIVATE -opt3)
+target_precompile_headers(foo3 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/empty3.h")
+target_sources(foo3 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/empty3.c")
+set_target_properties(foo3 PROPERTIES
+ SYSTEM_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/sys3"
+ AUTOMOC_MACRO_NAMES "MOC3"
+ AUTOUIC_OPTIONS "-uic3"
+ )
+
+add_executable(main main.c)
+target_link_libraries(main PRIVATE foo1)
+target_include_directories(main PRIVATE dirM)
+target_compile_definitions(main PRIVATE DEFM)
+target_compile_features(main PRIVATE cxx_std_20)
+target_compile_options(main PRIVATE -optM)
+target_precompile_headers(main PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/empty.h")
+set_target_properties(main PROPERTIES
+ AUTOMOC_MACRO_NAMES "MOCM"
+ AUTOUIC_OPTIONS "-uicM"
+ )
+
+file(GENERATE OUTPUT out.txt CONTENT "# file(GENERATE) produced:
+main INCLUDE_DIRECTORIES: '$<TARGET_PROPERTY:main,INCLUDE_DIRECTORIES>'
+main SYSTEM_INCLUDE_DIRECTORIES: '$<TARGET_PROPERTY:main,SYSTEM_INCLUDE_DIRECTORIES>'
+main COMPILE_DEFINITIONS: '$<TARGET_PROPERTY:main,COMPILE_DEFINITIONS>'
+main COMPILE_FEATURES: '$<TARGET_PROPERTY:main,COMPILE_FEATURES>'
+main COMPILE_OPTIONS: '$<TARGET_PROPERTY:main,COMPILE_OPTIONS>'
+main PRECOMPILE_HEADERS: '$<TARGET_PROPERTY:main,PRECOMPILE_HEADERS>'
+main SOURCES: '$<TARGET_PROPERTY:main,SOURCES>'
+main AUTOMOC_MACRO_NAMES: '$<TARGET_PROPERTY:main,AUTOMOC_MACRO_NAMES>'
+main AUTOUIC_OPTIONS: '$<TARGET_PROPERTY:main,AUTOUIC_OPTIONS>'
+")
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-check.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-check.cmake
new file mode 100644
index 0000000..7ea95b8
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-check.cmake
@@ -0,0 +1,8 @@
+set(expect [[
+# file\(GENERATE\) produced:
+main LINK_LIBRARIES: 'foo1' # not transitive
+main LINK_DIRECTORIES: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dirM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dir1;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dir2'
+main LINK_OPTIONS: '-optM;-opt1;-opt2'
+main LINK_DEPENDS: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-build/depM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-build/dep1;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-build/dep2'
+]])
+include(${CMAKE_CURRENT_LIST_DIR}/TransitiveLink-check-common.cmake)
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW.cmake
new file mode 100644
index 0000000..658dd84
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0166 NEW)
+include(TransitiveLink-common.cmake)
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD-check.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD-check.cmake
new file mode 100644
index 0000000..2d430c2
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD-check.cmake
@@ -0,0 +1,8 @@
+set(expect [[
+# file\(GENERATE\) produced:
+main LINK_LIBRARIES: 'foo1' # not transitive
+main LINK_DIRECTORIES: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dirM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dir1'
+main LINK_OPTIONS: '-optM;-opt1'
+main LINK_DEPENDS: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD-build/depM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD-build/dep1'
+]])
+include(${CMAKE_CURRENT_LIST_DIR}/TransitiveLink-check-common.cmake)
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD.cmake
new file mode 100644
index 0000000..a4a4599
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0166 OLD)
+include(TransitiveLink-common.cmake)
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check-common.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check-common.cmake
new file mode 100644
index 0000000..42e63bc
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check-common.cmake
@@ -0,0 +1,12 @@
+string(REGEX REPLACE "\r\n" "\n" expect "${expect}")
+string(REGEX REPLACE "\n+$" "" expect "${expect}")
+
+file(READ "${RunCMake_TEST_BINARY_DIR}/out.txt" 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/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-common.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-common.cmake
new file mode 100644
index 0000000..c120366
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-common.cmake
@@ -0,0 +1,42 @@
+enable_language(C)
+
+add_library(foo1 STATIC empty.c)
+target_link_libraries(foo1 PRIVATE foo2 foo3)
+target_link_directories(foo1 INTERFACE dir1)
+target_link_options(foo1 INTERFACE -opt1)
+set_target_properties(foo1 PROPERTIES
+ INTERFACE_LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/dep1"
+ )
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dep1" "")
+
+add_library(foo2 STATIC empty.c)
+target_link_directories(foo2 INTERFACE dir2)
+target_link_options(foo2 INTERFACE -opt2)
+set_target_properties(foo2 PROPERTIES
+ INTERFACE_LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/dep2"
+ )
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dep2" "")
+
+add_library(foo3 STATIC empty.c)
+target_link_directories(foo3 PRIVATE dir3)
+target_link_options(foo3 PRIVATE -opt3)
+set_target_properties(foo3 PROPERTIES
+ LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/dep3"
+ )
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dep3" "")
+
+add_executable(main main.c)
+target_link_libraries(main PRIVATE foo1)
+target_link_directories(main PRIVATE dirM)
+target_link_options(main PRIVATE -optM)
+set_target_properties(main PROPERTIES
+ LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/depM"
+ )
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/depM" "")
+
+file(GENERATE OUTPUT out.txt CONTENT "# file(GENERATE) produced:
+main LINK_LIBRARIES: '$<TARGET_PROPERTY:main,LINK_LIBRARIES>' # not transitive
+main LINK_DIRECTORIES: '$<TARGET_PROPERTY:main,LINK_DIRECTORIES>'
+main LINK_OPTIONS: '$<TARGET_PROPERTY:main,LINK_OPTIONS>'
+main LINK_DEPENDS: '$<TARGET_PROPERTY:main,LINK_DEPENDS>'
+")
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.h b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.h
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.c b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.c
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.h b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.h
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty2.h b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty2.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty2.h
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty3.h b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty3.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty3.h
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/main.c b/Tests/RunCMake/GenEx-TARGET_PROPERTY/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}