cmGeneratorExpressionDAGChecker: Simplify transitive property table

Refactor the table of builtin transitive properties to avoid
preprocessor-generated cascading-if blocks with duplicate code.
This commit is contained in:
Brad King
2024-04-29 14:25:34 -04:00
parent e8010b67c7
commit 79a3ae9a0d
6 changed files with 73 additions and 97 deletions

View File

@@ -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);

View File

@@ -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>
@@ -38,14 +38,12 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
, Content(content)
, Backtrace(std::move(backtrace))
{
static_cast<void>(contextLG);
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();
@@ -171,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);
@@ -224,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

View File

@@ -15,33 +15,6 @@ struct cmGeneratorExpressionContext;
class cmGeneratorTarget;
class cmLocalGenerator;
#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)
struct cmGeneratorExpressionDAGChecker
{
cmGeneratorExpressionDAGChecker(cmListFileBacktrace backtrace,
@@ -86,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; }

View File

@@ -2877,24 +2877,11 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
std::string interfacePropertyName;
bool isInterfaceProperty = false;
#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;
}
#undef POPULATE_INTERFACE_PROPERTY_NAME
bool evaluatingLinkLibraries = false;

View File

@@ -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,23 @@ 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 } },
{ "AUTOUIC_OPTIONS"_s, { "INTERFACE_AUTOUIC_OPTIONS"_s } },
{ "COMPILE_DEFINITIONS"_s, { "INTERFACE_COMPILE_DEFINITIONS"_s } },
{ "COMPILE_FEATURES"_s, { "INTERFACE_COMPILE_FEATURES"_s } },
{ "COMPILE_OPTIONS"_s, { "INTERFACE_COMPILE_OPTIONS"_s } },
{ "INCLUDE_DIRECTORIES"_s, { "INTERFACE_INCLUDE_DIRECTORIES"_s } },
{ "LINK_DEPENDS"_s, { "INTERFACE_LINK_DEPENDS"_s } },
{ "LINK_DIRECTORIES"_s, { "INTERFACE_LINK_DIRECTORIES"_s } },
{ "LINK_OPTIONS"_s, { "INTERFACE_LINK_OPTIONS"_s } },
{ "PRECOMPILE_HEADERS"_s, { "INTERFACE_PRECOMPILE_HEADERS"_s } },
{ "SOURCES"_s, { "INTERFACE_SOURCES"_s } },
{ "SYSTEM_INCLUDE_DIRECTORIES"_s,
{ "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES"_s } },
};
template <>
cmValue cmTargetPropertyComputer::GetSources<cmGeneratorTarget>(
cmGeneratorTarget const* tgt, cmMakefile const& /* mf */)
@@ -1517,6 +1535,28 @@ 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;
} 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 };
}
}
return result;
}
namespace {
enum class IncludeDirectoryFallBack

View File

@@ -15,6 +15,7 @@
#include <vector>
#include <cm/optional>
#include <cm/string_view>
#include "cmAlgorithms.h"
#include "cmComputeLinkInformation.h"
@@ -885,6 +886,17 @@ public:
cmGeneratorExpressionDAGChecker* dagCheckerParent,
LinkInterfaceFor interfaceFor) const;
struct TransitiveProperty
{
cm::string_view InterfaceName;
};
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;