Merge topic 'cps-link-only'

ebe487ea81 export: Allow export with LINK_ONLY library dependencies
13c7bb5b0c cmGeneratorExpression: Update strip function to collect parsed expressions

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !10522
This commit is contained in:
Brad King
2025-04-14 12:25:35 +00:00
committed by Kitware Robot
12 changed files with 164 additions and 31 deletions
+62 -23
View File
@@ -2,6 +2,7 @@
file LICENSE.rst or https://cmake.org/licensing for details. */
#include "cmExportPackageInfoGenerator.h"
#include <cstddef>
#include <memory>
#include <set>
#include <utility>
@@ -210,13 +211,15 @@ bool cmExportPackageInfoGenerator::GenerateInterfaceProperties(
}
namespace {
bool forbidGeneratorExpressions(std::string const& propertyName,
std::string const& propertyValue,
cmGeneratorTarget const* target)
bool ForbidGeneratorExpressions(
cmGeneratorTarget const* target, std::string const& propertyName,
std::string const& propertyValue, std::string& evaluatedValue,
std::map<std::string, std::vector<std::string>>& allowList)
{
std::string const& evaluatedValue = cmGeneratorExpression::Preprocess(
propertyValue, cmGeneratorExpression::StripAllGeneratorExpressions);
if (evaluatedValue != propertyValue) {
size_t const allowedExpressions = allowList.size();
evaluatedValue = cmGeneratorExpression::Collect(propertyValue, allowList);
if (evaluatedValue != propertyValue &&
allowList.size() > allowedExpressions) {
target->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("Property \"", propertyName, "\" of target \"",
@@ -224,8 +227,32 @@ bool forbidGeneratorExpressions(std::string const& propertyName,
"\" contains a generator expression. This is not allowed."));
return false;
}
// Forbid Nested Generator Expressions
for (auto const& genexp : allowList) {
for (auto const& value : genexp.second) {
if (value.find("$<") != std::string::npos) {
target->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat(
"$<", genexp.first, ":...> expression in \"", propertyName,
"\" of target \"", target->GetName(),
"\" contains a generator expression. This is not allowed."));
return false;
}
}
}
return true;
}
bool ForbidGeneratorExpressions(cmGeneratorTarget const* target,
std::string const& propertyName,
std::string const& propertyValue)
{
std::map<std::string, std::vector<std::string>> allowList;
std::string evaluatedValue;
return ForbidGeneratorExpressions(target, propertyName, propertyValue,
evaluatedValue, allowList);
}
}
bool cmExportPackageInfoGenerator::NoteLinkedTarget(
@@ -317,31 +344,43 @@ void cmExportPackageInfoGenerator::GenerateInterfaceLinkProperties(
return;
}
// TODO: Support $<LINK_ONLY>.
if (!forbidGeneratorExpressions(iter->first, iter->second, target)) {
// Extract any $<LINK_ONLY:...> from the link libraries, and assert that no
// other generator expressions are present.
std::map<std::string, std::vector<std::string>> allowList = { { "LINK_ONLY",
{} } };
std::string interfaceLinkLibraries;
if (!ForbidGeneratorExpressions(target, iter->first, iter->second,
interfaceLinkLibraries, allowList)) {
result = false;
return;
}
std::vector<std::string> buildRequires;
// std::vector<std::string> linkRequires; TODO
std::vector<std::string> linkLibraries;
std::vector<std::string> linkRequires;
std::vector<std::string> buildRequires;
for (auto const& name : cmList{ iter->second }) {
auto const& ti = this->LinkTargets.find(name);
if (ti != this->LinkTargets.end()) {
if (ti->second.empty()) {
result = false;
auto addLibraries = [this, &linkLibraries,
&result](std::vector<std::string> const& names,
std::vector<std::string>& output) -> void {
for (auto const& name : names) {
auto const& ti = this->LinkTargets.find(name);
if (ti != this->LinkTargets.end()) {
if (ti->second.empty()) {
result = false;
} else {
output.emplace_back(ti->second);
}
} else {
buildRequires.emplace_back(ti->second);
linkLibraries.emplace_back(name);
}
} else {
linkLibraries.emplace_back(name);
}
}
};
addLibraries(allowList["LINK_ONLY"], linkRequires);
addLibraries(cmList{ interfaceLinkLibraries }, buildRequires);
buildArray(component, "requires", buildRequires);
// buildArray(component, "link_requires", linkRequires); TODO
buildArray(component, "link_requires", linkRequires);
buildArray(component, "link_libraries", linkLibraries);
}
@@ -354,7 +393,7 @@ void cmExportPackageInfoGenerator::GenerateInterfaceCompileFeatures(
return;
}
if (!forbidGeneratorExpressions(iter->first, iter->second, target)) {
if (!ForbidGeneratorExpressions(target, iter->first, iter->second)) {
result = false;
return;
}
@@ -383,7 +422,7 @@ void cmExportPackageInfoGenerator::GenerateInterfaceCompileDefines(
}
// TODO: Support language-specific defines.
if (!forbidGeneratorExpressions(iter->first, iter->second, target)) {
if (!ForbidGeneratorExpressions(target, iter->first, iter->second)) {
result = false;
return;
}
@@ -414,7 +453,7 @@ void cmExportPackageInfoGenerator::GenerateInterfaceListProperty(
return;
}
if (!forbidGeneratorExpressions(prop, iter->second, target)) {
if (!ForbidGeneratorExpressions(target, prop, iter->second)) {
result = false;
return;
}
+34 -8
View File
@@ -5,6 +5,7 @@
#include <algorithm>
#include <cassert>
#include <memory>
#include <stack>
#include <utility>
#include <cm/string_view>
@@ -156,27 +157,40 @@ std::string cmGeneratorExpression::StripEmptyListElements(
return result;
}
static std::string stripAllGeneratorExpressions(std::string const& input)
static std::string extractAllGeneratorExpressions(
std::string const& input,
std::map<std::string, std::vector<std::string>>* collected)
{
std::string result;
std::string::size_type pos = 0;
std::string::size_type lastPos = pos;
int nestingLevel = 0;
// stack of { Generator Expression Name, Start Position of Value }
std::stack<std::pair<std::string, std::string::size_type>> genexps;
while ((pos = input.find("$<", lastPos)) != std::string::npos) {
result += input.substr(lastPos, pos - lastPos);
pos += 2;
nestingLevel = 1;
char const* c = input.c_str() + pos;
char const* cName = c;
char const* const cStart = c;
for (; *c; ++c) {
if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) {
++nestingLevel;
++c;
cName = c + 1;
continue;
}
if (c[0] == '>') {
--nestingLevel;
if (nestingLevel == 0) {
if (c[0] == ':' && cName) {
genexps.push({ input.substr(pos + (cName - cStart), c - cName),
pos + (c + 1 - cStart) });
cName = nullptr;
} else if (c[0] == '>') {
if (!cName && !genexps.empty()) {
if (collected) {
(*collected)[genexps.top().first].push_back(input.substr(
genexps.top().second, pos + c - cStart - genexps.top().second));
}
genexps.pop();
}
if (genexps.empty()) {
break;
}
}
@@ -188,12 +202,17 @@ static std::string stripAllGeneratorExpressions(std::string const& input)
pos += traversed;
lastPos = pos;
}
if (nestingLevel == 0) {
if (genexps.empty()) {
result += input.substr(lastPos);
}
return cmGeneratorExpression::StripEmptyListElements(result);
}
static std::string stripAllGeneratorExpressions(std::string const& input)
{
return extractAllGeneratorExpressions(input, nullptr);
}
static void prefixItems(std::string const& content, std::string& result,
cm::string_view const& prefix)
{
@@ -375,6 +394,13 @@ std::string cmGeneratorExpression::Preprocess(std::string const& input,
return std::string();
}
std::string cmGeneratorExpression::Collect(
std::string const& input,
std::map<std::string, std::vector<std::string>>& collected)
{
return extractAllGeneratorExpressions(input, &collected);
}
cm::string_view::size_type cmGeneratorExpression::Find(
cm::string_view const& input)
{
+4
View File
@@ -63,6 +63,10 @@ public:
PreprocessContext context,
cm::string_view importPrefix = {});
static std::string Collect(
std::string const& input,
std::map<std::string, std::vector<std::string>>& collected);
static void Split(std::string const& input,
std::vector<std::string>& output);