Merge topic 'link-feature-attributes-stabilization' into release-3.30

576567f028 Link feature attributes: stabilization
5617c34c31 Libraries processing: update configuration wording

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !9607
This commit is contained in:
Brad King
2024-06-24 13:21:59 +00:00
committed by Kitware Robot
58 changed files with 268 additions and 191 deletions

View File

@@ -202,8 +202,8 @@ bool IsFeatureSupported(cmMakefile* makefile, std::string const& linkLanguage,
return makefile->GetDefinition(featureSupported).IsOn();
}
// LINK_LIBRARY feature properties management
struct LinkLibraryFeaturePropertySet
// LINK_LIBRARY feature attributes management
struct LinkLibraryFeatureAttributeSet
{
std::set<cmStateEnums::TargetType> LibraryTypes = {
cmStateEnums::EXECUTABLE, cmStateEnums::STATIC_LIBRARY,
@@ -212,84 +212,88 @@ struct LinkLibraryFeaturePropertySet
};
std::set<std::string> Override;
enum UnicityKind
enum DeduplicationKind
{
Default,
Yes,
No
};
UnicityKind Unicity = Default;
DeduplicationKind Deduplication = Default;
};
std::map<std::string, LinkLibraryFeaturePropertySet>
LinkLibraryFeatureProperties;
const LinkLibraryFeaturePropertySet& GetLinkLibraryFeatureProperties(
std::map<std::string, LinkLibraryFeatureAttributeSet>
LinkLibraryFeatureAttributes;
const LinkLibraryFeatureAttributeSet& GetLinkLibraryFeatureAttributes(
cmMakefile* makefile, std::string const& linkLanguage,
const std::string& feature)
{
auto it = LinkLibraryFeatureProperties.find(feature);
if (it != LinkLibraryFeatureProperties.end()) {
auto it = LinkLibraryFeatureAttributes.find(feature);
if (it != LinkLibraryFeatureAttributes.end()) {
return it->second;
}
auto featurePropertiesVariable =
cmStrCat("CMAKE_", linkLanguage, "_LINK_LIBRARY_", feature, "_PROPERTIES");
auto featurePropertiesValues =
makefile->GetDefinition(featurePropertiesVariable);
if (featurePropertiesValues.IsEmpty()) {
auto featureAttributesVariable =
cmStrCat("CMAKE_", linkLanguage, "_LINK_LIBRARY_", feature, "_ATTRIBUTES");
auto featureAttributesValues =
makefile->GetDefinition(featureAttributesVariable);
if (featureAttributesValues.IsEmpty()) {
// try language agnostic definition
featurePropertiesVariable =
cmStrCat("CMAKE_LINK_LIBRARY_", feature, "_PROPERTIES");
featurePropertiesValues =
makefile->GetDefinition(featurePropertiesVariable);
featureAttributesVariable =
cmStrCat("CMAKE_LINK_LIBRARY_", feature, "_ATTRIBUTES");
featureAttributesValues =
makefile->GetDefinition(featureAttributesVariable);
}
if (!featurePropertiesValues.IsEmpty()) {
LinkLibraryFeaturePropertySet featureProperties;
if (!featureAttributesValues.IsEmpty()) {
LinkLibraryFeatureAttributeSet featureAttributes;
cmsys::RegularExpression processingOption{
"^(LIBRARY_TYPE|UNICITY|OVERRIDE)=((STATIC|SHARED|MODULE|EXECUTABLE)(,("
"^(LIBRARY_TYPE|DEDUPLICATION|OVERRIDE)=((STATIC|SHARED|MODULE|"
"EXECUTABLE)(,("
"STATIC|"
"SHARED|MODULE|EXECUTABLE)"
")*|YES|NO|DEFAULT|[A-Za-z0-9_]+(,[A-Za-z0-9_]+)*)$"
};
std::string errorMessage;
for (auto const& option : cmList{ featurePropertiesValues }) {
for (auto const& option : cmList{ featureAttributesValues }) {
if (processingOption.find(option)) {
if (processingOption.match(1) == "LIBRARY_TYPE") {
featureProperties.LibraryTypes.clear();
featureAttributes.LibraryTypes.clear();
for (auto const& value :
cmTokenize(processingOption.match(2), ","_s)) {
if (value == "STATIC") {
featureProperties.LibraryTypes.emplace(
featureAttributes.LibraryTypes.emplace(
cmStateEnums::STATIC_LIBRARY);
} else if (value == "SHARED") {
featureProperties.LibraryTypes.emplace(
featureAttributes.LibraryTypes.emplace(
cmStateEnums::SHARED_LIBRARY);
} else if (value == "MODULE") {
featureProperties.LibraryTypes.emplace(
featureAttributes.LibraryTypes.emplace(
cmStateEnums::MODULE_LIBRARY);
} else if (value == "EXECUTABLE") {
featureProperties.LibraryTypes.emplace(cmStateEnums::EXECUTABLE);
featureAttributes.LibraryTypes.emplace(cmStateEnums::EXECUTABLE);
} else {
errorMessage += cmStrCat(" ", option, '\n');
break;
}
}
// Always add UNKNOWN type
featureProperties.LibraryTypes.emplace(
featureAttributes.LibraryTypes.emplace(
cmStateEnums::UNKNOWN_LIBRARY);
} else if (processingOption.match(1) == "UNICITY") {
} else if (processingOption.match(1) == "DEDUPLICATION") {
if (processingOption.match(2) == "YES") {
featureProperties.Unicity = LinkLibraryFeaturePropertySet::Yes;
featureAttributes.Deduplication =
LinkLibraryFeatureAttributeSet::Yes;
} else if (processingOption.match(2) == "NO") {
featureProperties.Unicity = LinkLibraryFeaturePropertySet::No;
featureAttributes.Deduplication =
LinkLibraryFeatureAttributeSet::No;
} else if (processingOption.match(2) == "DEFAULT") {
featureProperties.Unicity = LinkLibraryFeaturePropertySet::Default;
featureAttributes.Deduplication =
LinkLibraryFeatureAttributeSet::Default;
} else {
errorMessage += cmStrCat(" ", option, '\n');
}
} else if (processingOption.match(1) == "OVERRIDE") {
featureProperties.Override.clear();
featureAttributes.Override.clear();
auto values = cmTokenize(processingOption.match(2), ","_s);
featureProperties.Override.insert(values.begin(), values.end());
featureAttributes.Override.insert(values.begin(), values.end());
}
} else {
errorMessage += cmStrCat(" ", option, '\n');
@@ -298,14 +302,14 @@ const LinkLibraryFeaturePropertySet& GetLinkLibraryFeatureProperties(
if (!errorMessage.empty()) {
makefile->GetCMakeInstance()->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("Erroneous option(s) for '", featurePropertiesVariable,
cmStrCat("Erroneous option(s) for '", featureAttributesVariable,
"':\n", errorMessage));
}
return LinkLibraryFeatureProperties.emplace(feature, featureProperties)
return LinkLibraryFeatureAttributes.emplace(feature, featureAttributes)
.first->second;
}
return LinkLibraryFeatureProperties
.emplace(feature, LinkLibraryFeaturePropertySet{})
return LinkLibraryFeatureAttributes
.emplace(feature, LinkLibraryFeatureAttributeSet{})
.first->second;
}
@@ -376,8 +380,10 @@ public:
case cmPolicies::NEW: {
if (auto libProcessing = makefile->GetDefinition(cmStrCat(
"CMAKE_", linkLanguage, "_LINK_LIBRARIES_PROCESSING"))) {
// UNICITY keyword is just for compatibility with previous
// implementation
cmsys::RegularExpression processingOption{
"^(ORDER|UNICITY)=(FORWARD|REVERSE|ALL|NONE|SHARED)$"
"^(ORDER|UNICITY|DEDUPLICATION)=(FORWARD|REVERSE|ALL|NONE|SHARED)$"
};
std::string errorMessage;
for (auto const& option : cmList{ libProcessing }) {
@@ -390,13 +396,14 @@ public:
} else {
errorMessage += cmStrCat(" ", option, '\n');
}
} else if (processingOption.match(1) == "UNICITY") {
} else if (processingOption.match(1) == "UNICITY" ||
processingOption.match(1) == "DEDUPLICATION") {
if (processingOption.match(2) == "ALL") {
this->Unicity = All;
this->Deduplication = All;
} else if (processingOption.match(2) == "NONE") {
this->Unicity = None;
this->Deduplication = None;
} else if (processingOption.match(2) == "SHARED") {
this->Unicity = Shared;
this->Deduplication = Shared;
} else {
errorMessage += cmStrCat(" ", option, '\n');
}
@@ -499,7 +506,7 @@ private:
Reverse
};
enum UnicityKind
enum DeduplicationKind
{
None,
Shared,
@@ -509,22 +516,23 @@ private:
bool IncludeEntry(LinkEntry const& entry) const
{
if (entry.Feature != cmComputeLinkDepends::LinkEntry::DEFAULT) {
auto const& featureProperties = GetLinkLibraryFeatureProperties(
auto const& featureAttributes = GetLinkLibraryFeatureAttributes(
this->Target->Makefile, this->LinkLanguage, entry.Feature);
if ((entry.Target == nullptr ||
featureProperties.LibraryTypes.find(entry.Target->GetType()) !=
featureProperties.LibraryTypes.end()) &&
featureProperties.Unicity !=
LinkLibraryFeaturePropertySet::Default) {
return featureProperties.Unicity == LinkLibraryFeaturePropertySet::No;
featureAttributes.LibraryTypes.find(entry.Target->GetType()) !=
featureAttributes.LibraryTypes.end()) &&
featureAttributes.Deduplication !=
LinkLibraryFeatureAttributeSet::Default) {
return featureAttributes.Deduplication ==
LinkLibraryFeatureAttributeSet::No;
}
}
return this->Unicity == None ||
(this->Unicity == Shared &&
return this->Deduplication == None ||
(this->Deduplication == Shared &&
(entry.Target == nullptr ||
entry.Target->GetType() != cmStateEnums::SHARED_LIBRARY)) ||
(this->Unicity == All && entry.Kind != LinkEntry::Library);
(this->Deduplication == All && entry.Kind != LinkEntry::Library);
}
template <typename Range>
@@ -539,7 +547,7 @@ private:
}
OrderKind Order = Reverse;
UnicityKind Unicity = Shared;
DeduplicationKind Deduplication = Shared;
const cmGeneratorTarget* Target;
const std::string& LinkLanguage;
EntryVector& Entries;
@@ -1121,27 +1129,29 @@ void cmComputeLinkDepends::AddLinkEntries(size_t depender_index,
" library '", entry.Item.Value, "'."),
this->Target->GetBacktrace());
}
// check if feature is applicable to this item
if (itemFeature != LinkEntry::DEFAULT && entry.Target != nullptr) {
auto const& featureAttributes = GetLinkLibraryFeatureAttributes(
this->Makefile, this->LinkLanguage, itemFeature);
if (featureAttributes.LibraryTypes.find(entry.Target->GetType()) ==
featureAttributes.LibraryTypes.end()) {
supportedItem = false;
this->CMakeInstance->IssueMessage(
MessageType::AUTHOR_WARNING,
cmStrCat("The feature '", itemFeature,
"', specified as part of a generator-expression "
"'$<LINK_LIBRARY:",
itemFeature, ">', will not be applied to the ",
cmState::GetTargetTypeName(entry.Target->GetType()), " '",
entry.Item.Value, "'."),
this->Target->GetBacktrace());
}
}
if (ale.second) {
// current item not yet defined
entry.Feature = itemFeature;
if (itemFeature != LinkEntry::DEFAULT && entry.Target != nullptr) {
auto const& featureProperties = GetLinkLibraryFeatureProperties(
this->Makefile, this->LinkLanguage, itemFeature);
if (featureProperties.LibraryTypes.find(entry.Target->GetType()) ==
featureProperties.LibraryTypes.end()) {
supportedItem = false;
entry.Feature = LinkEntry::DEFAULT;
this->CMakeInstance->IssueMessage(
MessageType::AUTHOR_WARNING,
cmStrCat("The feature '", itemFeature,
"', specified as part of a generator-expression "
"'$<LINK_LIBRARY:",
itemFeature, ">', will not be applied to the ",
cmState::GetTargetTypeName(entry.Target->GetType()), " '",
entry.Item.Value, "'."),
this->Target->GetBacktrace());
}
if (!supportedItem) {
entry.Feature = LinkEntry::DEFAULT;
}
}
@@ -1170,38 +1180,50 @@ void cmComputeLinkDepends::AddLinkEntries(size_t depender_index,
if (entry.Feature != itemFeature) {
bool incompatibleFeatures = true;
// check if an override is possible
auto const& entryFeatureProperties = GetLinkLibraryFeatureProperties(
auto const& entryFeatureAttributes = GetLinkLibraryFeatureAttributes(
this->Makefile, this->LinkLanguage, entry.Feature);
auto const& itemFeatureProperties = GetLinkLibraryFeatureProperties(
auto const& itemFeatureAttributes = GetLinkLibraryFeatureAttributes(
this->Makefile, this->LinkLanguage, itemFeature);
if (entryFeatureProperties.Override.empty() &&
!itemFeatureProperties.Override.empty() &&
itemFeatureProperties.Override.find(entry.Feature) !=
itemFeatureProperties.Override.end()) {
entry.Feature = itemFeature;
incompatibleFeatures = false;
} else if (!entryFeatureProperties.Override.empty() &&
itemFeatureProperties.Override.empty() &&
entryFeatureProperties.Override.find(itemFeature) !=
entryFeatureProperties.Override.end()) {
incompatibleFeatures = false;
}
if (incompatibleFeatures) {
// incompatibles features occurred
if (itemFeatureAttributes.Override.find(entry.Feature) !=
itemFeatureAttributes.Override.end() &&
entryFeatureAttributes.Override.find(itemFeature) !=
entryFeatureAttributes.Override.end()) {
// features override each other
this->CMakeInstance->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("Impossible to link target '", this->Target->GetName(),
"' because the link item '", entry.Item.Value,
"', specified ",
(itemFeature == LinkEntry::DEFAULT
? "without any feature or 'DEFAULT' feature"
: cmStrCat("with the feature '", itemFeature, '\'')),
", has already occurred ",
(entry.Feature == LinkEntry::DEFAULT
? "without any feature or 'DEFAULT' feature"
: cmStrCat("with the feature '", entry.Feature, '\'')),
", which is not allowed."),
"' is specified with the features '", itemFeature,
"' and '", entry.Feature, "'",
", and both have an 'OVERRIDE' attribute that overrides "
"the other. Such cycles are not allowed."),
this->Target->GetBacktrace());
} else {
if (itemFeatureAttributes.Override.find(entry.Feature) !=
itemFeatureAttributes.Override.end()) {
entry.Feature = itemFeature;
incompatibleFeatures = false;
} else if (entryFeatureAttributes.Override.find(itemFeature) !=
entryFeatureAttributes.Override.end()) {
incompatibleFeatures = false;
}
if (incompatibleFeatures) {
// incompatibles features occurred
this->CMakeInstance->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat(
"Impossible to link target '", this->Target->GetName(),
"' because the link item '", entry.Item.Value, "', specified ",
(itemFeature == LinkEntry::DEFAULT
? "without any feature or 'DEFAULT' feature"
: cmStrCat("with the feature '", itemFeature, '\'')),
", has already occurred ",
(entry.Feature == LinkEntry::DEFAULT
? "without any feature or 'DEFAULT' feature"
: cmStrCat("with the feature '", entry.Feature, '\'')),
", which is not allowed."),
this->Target->GetBacktrace());
}
}
}
}