mirror of
https://github.com/Kitware/CMake.git
synced 2026-05-01 03:29:18 -05:00
Merge topic 'genex-link-properties'
ddb9442f48GenEx: Fix TARGET_PROPERTY evaluation of transitive link properties862b8e28adGenEx: Teach TARGET_PROPERTY evaluation to optionally pierce LINK_ONLY8d1d6a1437Tests: Cover TARGET_PROPERTY genex evaluation of transitive link propertiesabf607c2ecTests: Cover TARGET_PROPERTY genex evaluation of transitive build properties7d3d728a72Help: Clarify CMP0099 documentation and summary text79a3ae9a0dcmGeneratorExpressionDAGChecker: Simplify transitive property tablee8010b67c7cmGeneratorExpressionDAGChecker: Make local generator available in constructorb36fb3f6f1cmGeneratorExpressionNode: Remove outdated lint suppression Acked-by: Kitware Robot <kwrobot@kitware.com> Tested-by: buildbot <buildbot@kitware.com> Merge-request: !9473
This commit is contained in:
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+14
-5
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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`.
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
+7
-3
@@ -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) \
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
@@ -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>'
|
||||
")
|
||||
@@ -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)
|
||||
@@ -0,0 +1,2 @@
|
||||
cmake_policy(SET CMP0166 NEW)
|
||||
include(TransitiveLink-common.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)
|
||||
@@ -0,0 +1,2 @@
|
||||
cmake_policy(SET CMP0166 OLD)
|
||||
include(TransitiveLink-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()
|
||||
@@ -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>'
|
||||
")
|
||||
@@ -0,0 +1,4 @@
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user