mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-06 13:51:33 -06:00
export: Allow export with LINK_ONLY library dependencies
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,6 @@
|
||||
CMake Error in CMakeLists.txt:
|
||||
Property "INTERFACE_LINK_LIBRARIES" of target "bar" contains a generator
|
||||
expression. This is not allowed.
|
||||
|
||||
|
||||
CMake Generate step failed. Build files cannot be regenerated correctly.
|
||||
@@ -0,0 +1,11 @@
|
||||
project(LinkInterfaceGeneratorExpression CXX)
|
||||
|
||||
add_library(foo foo.cxx)
|
||||
add_library(bar foo.cxx)
|
||||
target_link_libraries(bar $<1:foo>)
|
||||
|
||||
install(TARGETS foo EXPORT foo)
|
||||
export(EXPORT foo PACKAGE_INFO foo)
|
||||
|
||||
install(TARGETS bar EXPORT bar)
|
||||
export(EXPORT bar PACKAGE_INFO bar)
|
||||
12
Tests/RunCMake/ExportPackageInfo/LinkOnly-check.cmake
Normal file
12
Tests/RunCMake/ExportPackageInfo/LinkOnly-check.cmake
Normal file
@@ -0,0 +1,12 @@
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
|
||||
|
||||
set(out_dir "${RunCMake_BINARY_DIR}/LinkOnly-build")
|
||||
|
||||
file(READ "${out_dir}/bar.cps" content)
|
||||
string(JSON component GET "${content}" "components" "bar")
|
||||
expect_array("${component}" 2 "link_requires")
|
||||
expect_value("${component}" "foo:linkOnlyOne" "link_requires" 0)
|
||||
expect_value("${component}" "foo:linkOnlyTwo" "link_requires" 1)
|
||||
expect_array("${component}" 1 "requires")
|
||||
expect_value("${component}" "foo:foo" "requires" 0)
|
||||
expect_missing("${component}" "foo:foo" "link_libraries")
|
||||
13
Tests/RunCMake/ExportPackageInfo/LinkOnly.cmake
Normal file
13
Tests/RunCMake/ExportPackageInfo/LinkOnly.cmake
Normal file
@@ -0,0 +1,13 @@
|
||||
project(LinkOnly CXX)
|
||||
|
||||
add_library(linkOnlyOne foo.cxx)
|
||||
add_library(linkOnlyTwo foo.cxx)
|
||||
add_library(foo foo.cxx)
|
||||
add_library(bar foo.cxx)
|
||||
target_link_libraries(bar $<LINK_ONLY:linkOnlyOne> $<LINK_ONLY:linkOnlyTwo> foo)
|
||||
|
||||
install(TARGETS foo linkOnlyOne linkOnlyTwo EXPORT foo)
|
||||
export(EXPORT foo PACKAGE_INFO foo)
|
||||
|
||||
install(TARGETS bar EXPORT bar)
|
||||
export(EXPORT bar PACKAGE_INFO bar)
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,6 @@
|
||||
CMake Error in CMakeLists.txt:
|
||||
\$<LINK_ONLY:...> expression in "INTERFACE_LINK_LIBRARIES" of target "bar"
|
||||
contains a generator expression. This is not allowed.
|
||||
|
||||
|
||||
CMake Generate step failed. Build files cannot be regenerated correctly.
|
||||
11
Tests/RunCMake/ExportPackageInfo/LinkOnlyRecursive.cmake
Normal file
11
Tests/RunCMake/ExportPackageInfo/LinkOnlyRecursive.cmake
Normal file
@@ -0,0 +1,11 @@
|
||||
project(LinkOnly CXX)
|
||||
|
||||
add_library(foo foo.cxx)
|
||||
add_library(bar foo.cxx)
|
||||
target_link_libraries(bar $<LINK_ONLY:$<LINK_ONLY:foo>>)
|
||||
|
||||
install(TARGETS foo EXPORT foo)
|
||||
export(EXPORT foo PACKAGE_INFO foo)
|
||||
|
||||
install(TARGETS bar EXPORT bar)
|
||||
export(EXPORT bar PACKAGE_INFO bar)
|
||||
@@ -24,6 +24,8 @@ run_cmake(ReferencesWronglyImportedTarget)
|
||||
run_cmake(ReferencesWronglyNamespacedTarget)
|
||||
run_cmake(DependsMultipleDifferentNamespace)
|
||||
run_cmake(DependsMultipleDifferentSets)
|
||||
run_cmake(LinkInterfaceGeneratorExpression)
|
||||
run_cmake(LinkOnlyRecursive)
|
||||
|
||||
# Test functionality
|
||||
run_cmake(Appendix)
|
||||
@@ -35,3 +37,4 @@ run_cmake(LowerCaseFile)
|
||||
run_cmake(Requirements)
|
||||
run_cmake(TargetTypes)
|
||||
run_cmake(DependsMultiple)
|
||||
run_cmake(LinkOnly)
|
||||
|
||||
Reference in New Issue
Block a user