1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-15 12:16:40 +08:00

CPS: Add Symbolic Components

Adds support for "symbolic" components, which represent feature-level
capabilities of a package that do not correspond to actual build targets.
These are modeled as pseudo-targets, using the INTERFACE type as a base,
and can be queried via:

  get_target_property(... <tgt> "SYMBOLIC")

This enables consumers to declare requirements on optional features
(e.g., SSL support) even when they do not map to concrete targets.

Fixes: #27187
This commit is contained in:
Taylor Sasser
2025-09-01 08:52:15 -04:00
parent 03284e018f
commit d92b6c3e20
44 changed files with 312 additions and 16 deletions

View File

@@ -196,6 +196,30 @@ Interface Libraries
call are ``PRIVATE`` to the interface library and do not appear in its call are ``PRIVATE`` to the interface library and do not appear in its
:prop_tgt:`INTERFACE_SOURCES` target property. :prop_tgt:`INTERFACE_SOURCES` target property.
.. signature::
add_library(<name> INTERFACE SYMBOLIC)
:target: INTERFACE-SYMBOLIC
.. versionadded:: 4.2
Add a symbolic :ref:`Interface Library <Interface Libraries>` target.
Symbolic interface libraries are useful for representing optional components
or features in a package. They have no usage requirements, do not compile
sources, and do not produce a library artifact on disk, but they may be
exported and installed. They can also be tested for existence with the
regular :command:`if(TARGET)` subcommand.
A symbolic interface library may be used as a linkable target to enforce the
presence of optional components in a dependency. For example, if a library
``libgui`` may or may not provide a feature ``widget``, a consumer package
can link against ``widget`` to express that it requires this component to be
available. This allows :command:`find_package` calls that declare required
components to be validated by linking against the corresponding symbolic
targets.
A symbolic interface library has the :prop_tgt:`SYMBOLIC` target property
set to true.
.. _`add_library imported libraries`: .. _`add_library imported libraries`:
Imported Libraries Imported Libraries

View File

@@ -417,6 +417,7 @@ Properties on Targets
/prop_tgt/Swift_LANGUAGE_VERSION /prop_tgt/Swift_LANGUAGE_VERSION
/prop_tgt/Swift_MODULE_DIRECTORY /prop_tgt/Swift_MODULE_DIRECTORY
/prop_tgt/Swift_MODULE_NAME /prop_tgt/Swift_MODULE_NAME
/prop_tgt/SYMBOLIC
/prop_tgt/SYSTEM /prop_tgt/SYSTEM
/prop_tgt/TEST_LAUNCHER /prop_tgt/TEST_LAUNCHER
/prop_tgt/TRANSITIVE_COMPILE_PROPERTIES /prop_tgt/TRANSITIVE_COMPILE_PROPERTIES

View File

@@ -0,0 +1,11 @@
SYMBOLIC
--------
.. versionadded:: 4.2
Read-only indication of whether a target is ``SYMBOLIC``.
Symbolic targets are created by calls to
:command:`add_library(INTERFACE SYMBOLIC) <add_library(INTERFACE-SYMBOLIC)>`.
They are useful for packages to represent additional **components** or
**feature selectors** that consumers can request via ``find_package()``.

View File

@@ -33,6 +33,7 @@ bool cmAddLibraryCommand(std::vector<std::string> const& args,
bool excludeFromAll = false; bool excludeFromAll = false;
bool importTarget = false; bool importTarget = false;
bool importGlobal = false; bool importGlobal = false;
bool symbolicTarget = false;
auto s = args.begin(); auto s = args.begin();
@@ -117,6 +118,9 @@ bool cmAddLibraryCommand(std::vector<std::string> const& args,
} else if (*s == "EXCLUDE_FROM_ALL") { } else if (*s == "EXCLUDE_FROM_ALL") {
++s; ++s;
excludeFromAll = true; excludeFromAll = true;
} else if (*s == "SYMBOLIC") {
++s;
symbolicTarget = true;
} else if (*s == "IMPORTED") { } else if (*s == "IMPORTED") {
++s; ++s;
importTarget = true; importTarget = true;
@@ -223,9 +227,9 @@ bool cmAddLibraryCommand(std::vector<std::string> const& args,
} }
/* ideally we should check whether for the linker language of the target /* ideally we should check whether for the linker language of the target
CMAKE_${LANG}_CREATE_SHARED_LIBRARY is defined and if not default to CMAKE_${LANG}_CREATE_SHARED_LIBRARY is defined and if not default to
STATIC. But at this point we know only the name of the target, but not STATIC. But at this point we know only the name of the target, but not
yet its linker language. */ yet its linker language. */
if ((type == cmStateEnums::SHARED_LIBRARY || if ((type == cmStateEnums::SHARED_LIBRARY ||
type == cmStateEnums::MODULE_LIBRARY) && type == cmStateEnums::MODULE_LIBRARY) &&
!mf.GetState()->GetGlobalPropertyAsBool("TARGET_SUPPORTS_SHARED_LIBS")) { !mf.GetState()->GetGlobalPropertyAsBool("TARGET_SUPPORTS_SHARED_LIBS")) {
@@ -282,7 +286,8 @@ bool cmAddLibraryCommand(std::vector<std::string> const& args,
} }
// Create the imported target. // Create the imported target.
mf.AddImportedTarget(libName, type, importGlobal); cmTarget* target = mf.AddImportedTarget(libName, type, importGlobal);
target->SetSymbolic(symbolicTarget);
return true; return true;
} }
@@ -312,8 +317,15 @@ bool cmAddLibraryCommand(std::vector<std::string> const& args,
} }
} }
if (symbolicTarget && type != cmStateEnums::INTERFACE_LIBRARY) {
status.SetError(
"SYMBOLIC option may only be used with INTERFACE libraries");
return false;
}
std::vector<std::string> srcs(s, args.end()); std::vector<std::string> srcs(s, args.end());
mf.AddLibrary(libName, type, srcs, excludeFromAll); cmTarget* target = mf.AddLibrary(libName, type, srcs, excludeFromAll);
target->SetSymbolic(symbolicTarget);
return true; return true;
} }

View File

@@ -292,7 +292,20 @@ void cmExportCMakeConfigGenerator::GenerateImportTargetCode(
os << "add_library(" << targetName << " OBJECT IMPORTED)\n"; os << "add_library(" << targetName << " OBJECT IMPORTED)\n";
break; break;
case cmStateEnums::INTERFACE_LIBRARY: case cmStateEnums::INTERFACE_LIBRARY:
os << "add_library(" << targetName << " INTERFACE IMPORTED)\n"; if (target->IsSymbolic()) {
os << "if(CMAKE_VERSION VERSION_GREATER_EQUAL \""
<< CMake_VERSION_DEVEL(4, 2)
<< "\")\n"
" add_library("
<< targetName << " INTERFACE SYMBOLIC IMPORTED)\n"
<< "elseif(CMAKE_VERSION VERSION_GREATER_EQUAL 3.2.0)\n"
<< " add_library(" << targetName << " INTERFACE IMPORTED)\n"
<< " set_target_properties(" << targetName
<< " PROPERTIES SYMBOLIC TRUE)\n"
<< "endif()\n";
} else {
os << "add_library(" << targetName << " INTERFACE IMPORTED)\n";
}
break; break;
default: // should never happen default: // should never happen
break; break;

View File

@@ -182,6 +182,7 @@ Json::Value* cmExportPackageInfoGenerator::GenerateImportTarget(
Json::Value& component = components[name]; Json::Value& component = components[name];
Json::Value& type = component["type"]; Json::Value& type = component["type"];
switch (targetType) { switch (targetType) {
case cmStateEnums::EXECUTABLE: case cmStateEnums::EXECUTABLE:
type = "executable"; type = "executable";
@@ -196,7 +197,7 @@ Json::Value* cmExportPackageInfoGenerator::GenerateImportTarget(
type = "module"; type = "module";
break; break;
case cmStateEnums::INTERFACE_LIBRARY: case cmStateEnums::INTERFACE_LIBRARY:
type = "interface"; type = target->IsSymbolic() ? "symbolic" : "interface";
break; break;
default: default:
type = "unknown"; type = "unknown";

View File

@@ -1153,6 +1153,11 @@ bool cmGeneratorTarget::IsImportedGloballyVisible() const
return this->Target->IsImportedGloballyVisible(); return this->Target->IsImportedGloballyVisible();
} }
bool cmGeneratorTarget::IsSymbolic() const
{
return this->Target->IsSymbolic();
}
bool cmGeneratorTarget::IsForeign() const bool cmGeneratorTarget::IsForeign() const
{ {
return this->Target->IsForeign(); return this->Target->IsForeign();

View File

@@ -70,6 +70,7 @@ public:
bool IsImported() const; bool IsImported() const;
bool IsImportedGloballyVisible() const; bool IsImportedGloballyVisible() const;
bool IsForeign() const; bool IsForeign() const;
bool IsSymbolic() const;
bool CanCompileSources() const; bool CanCompileSources() const;
bool HasKnownRuntimeArtifactLocation(std::string const& config) const; bool HasKnownRuntimeArtifactLocation(std::string const& config) const;
std::string const& GetLocation(std::string const& config) const; std::string const& GetLocation(std::string const& config) const;

View File

@@ -773,7 +773,9 @@ bool cmPackageInfoReader::ImportTargets(cmMakefile* makefile,
cmTarget* target = nullptr; cmTarget* target = nullptr;
if (type == "symbolic"_s) { if (type == "symbolic"_s) {
// TODO target = this->AddLibraryComponent(
makefile, cmStateEnums::INTERFACE_LIBRARY, fullName, *ci, package);
target->SetSymbolic(true);
} else if (type == "dylib"_s) { } else if (type == "dylib"_s) {
target = this->AddLibraryComponent( target = this->AddLibraryComponent(
makefile, cmStateEnums::SHARED_LIBRARY, fullName, *ci, package); makefile, cmStateEnums::SHARED_LIBRARY, fullName, *ci, package);

View File

@@ -634,7 +634,13 @@ bool HandleTargetMode(cmExecutionStatus& status,
status.SetError("can not be used on an ALIAS target."); status.SetError("can not be used on an ALIAS target.");
return false; return false;
} }
if (cmTarget* target = status.GetMakefile().FindTargetToUse(name)) { if (cmTarget* target = status.GetMakefile().FindTargetToUse(name)) {
if (target->IsSymbolic()) {
status.SetError("can not be used on a SYMBOLIC target.");
return false;
}
// Handle the current target. // Handle the current target.
if (!HandleTarget(target, status.GetMakefile(), propertyName, if (!HandleTarget(target, status.GetMakefile(), propertyName,
propertyValue, appendAsString, appendMode, remove)) { propertyValue, appendAsString, appendMode, remove)) {

View File

@@ -40,6 +40,10 @@ bool cmSetTargetPropertiesCommand(std::vector<std::string> const& args,
return false; return false;
} }
if (cmTarget* target = mf.FindTargetToUse(tname)) { if (cmTarget* target = mf.FindTargetToUse(tname)) {
if (target->IsSymbolic()) {
status.SetError("can not be used on a SYMBOLIC target.");
return false;
}
// loop through all the props and set them // loop through all the props and set them
for (auto k = propsIter + 1; k != args.end(); k += 2) { for (auto k = propsIter + 1; k != args.end(); k += 2) {
target->SetProperty(*k, *(k + 1)); target->SetProperty(*k, *(k + 1));

View File

@@ -608,6 +608,7 @@ public:
bool IsAndroid; bool IsAndroid;
bool BuildInterfaceIncludesAppended; bool BuildInterfaceIncludesAppended;
bool PerConfig; bool PerConfig;
bool IsSymbolic;
cmTarget::Visibility TargetVisibility; cmTarget::Visibility TargetVisibility;
std::set<BT<std::pair<std::string, bool>>> Utilities; std::set<BT<std::pair<std::string, bool>>> Utilities;
std::set<std::string> CodegenDependencies; std::set<std::string> CodegenDependencies;
@@ -885,6 +886,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
this->impl->IsAIX = false; this->impl->IsAIX = false;
this->impl->IsApple = false; this->impl->IsApple = false;
this->impl->IsAndroid = false; this->impl->IsAndroid = false;
this->impl->IsSymbolic = false;
this->impl->TargetVisibility = vis; this->impl->TargetVisibility = vis;
this->impl->BuildInterfaceIncludesAppended = false; this->impl->BuildInterfaceIncludesAppended = false;
this->impl->PerConfig = (perConfig == PerConfig::Yes); this->impl->PerConfig = (perConfig == PerConfig::Yes);
@@ -1946,6 +1948,7 @@ MAKE_PROP(LINK_LIBRARIES);
MAKE_PROP(MANUALLY_ADDED_DEPENDENCIES); MAKE_PROP(MANUALLY_ADDED_DEPENDENCIES);
MAKE_PROP(NAME); MAKE_PROP(NAME);
MAKE_PROP(SOURCES); MAKE_PROP(SOURCES);
MAKE_PROP(SYMBOLIC);
MAKE_PROP(TYPE); MAKE_PROP(TYPE);
MAKE_PROP(BINARY_DIR); MAKE_PROP(BINARY_DIR);
MAKE_PROP(SOURCE_DIR); MAKE_PROP(SOURCE_DIR);
@@ -2047,6 +2050,7 @@ bool IsSettableProperty(cmMakefile* context, cmTarget* target,
{ "MANUALLY_ADDED_DEPENDENCIES", { ROC::All } }, { "MANUALLY_ADDED_DEPENDENCIES", { ROC::All } },
{ "NAME", { ROC::All } }, { "NAME", { ROC::All } },
{ "SOURCES", { ROC::Imported } }, { "SOURCES", { ROC::Imported } },
{ "SYMBOLIC", { ROC::All } },
{ "TYPE", { ROC::All } }, { "TYPE", { ROC::All } },
{ "ALIAS_GLOBAL", { ROC::All, cmPolicies::CMP0160 } }, { "ALIAS_GLOBAL", { ROC::All, cmPolicies::CMP0160 } },
{ "BINARY_DIR", { ROC::All, cmPolicies::CMP0160 } }, { "BINARY_DIR", { ROC::All, cmPolicies::CMP0160 } },
@@ -2067,6 +2071,11 @@ bool IsSettableProperty(cmMakefile* context, cmTarget* target,
} }
} }
void cmTarget::SetSymbolic(bool const value)
{
this->impl->IsSymbolic = value;
}
void cmTarget::SetProperty(std::string const& prop, cmValue value) void cmTarget::SetProperty(std::string const& prop, cmValue value)
{ {
if (!IsSettableProperty(this->impl->Makefile, this, prop)) { if (!IsSettableProperty(this->impl->Makefile, this, prop)) {
@@ -2606,6 +2615,7 @@ cmValue cmTarget::GetProperty(std::string const& prop) const
propBINARY_DIR, propBINARY_DIR,
propSOURCE_DIR, propSOURCE_DIR,
propSOURCES, propSOURCES,
propSYMBOLIC,
propINTERFACE_LINK_LIBRARIES, propINTERFACE_LINK_LIBRARIES,
propINTERFACE_LINK_LIBRARIES_DIRECT, propINTERFACE_LINK_LIBRARIES_DIRECT,
propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE, propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE,
@@ -2626,6 +2636,10 @@ cmValue cmTarget::GetProperty(std::string const& prop) const
return cmValue(propertyIter->second.Value); return cmValue(propertyIter->second.Value);
} }
if (prop == propSYMBOLIC) {
return this->IsSymbolic() ? cmValue(propTRUE) : cmValue(propFALSE);
}
UsageRequirementProperty const* usageRequirements[] = { UsageRequirementProperty const* usageRequirements[] = {
&this->impl->IncludeDirectories, &this->impl->IncludeDirectories,
&this->impl->CompileOptions, &this->impl->CompileOptions,
@@ -2760,6 +2774,11 @@ bool cmTarget::IsApple() const
return this->impl->IsApple; return this->impl->IsApple;
} }
bool cmTarget::IsSymbolic() const
{
return this->impl->IsSymbolic;
}
bool cmTarget::IsNormal() const bool cmTarget::IsNormal() const
{ {
switch (this->impl->TargetVisibility) { switch (this->impl->TargetVisibility) {

View File

@@ -193,6 +193,8 @@ public:
//! Get the utilities used by this target //! Get the utilities used by this target
std::set<BT<std::pair<std::string, bool>>> const& GetUtilities() const; std::set<BT<std::pair<std::string, bool>>> const& GetUtilities() const;
void SetSymbolic(bool value);
//! Set/Get a property of this target file //! Set/Get a property of this target file
void SetProperty(std::string const& prop, cmValue value); void SetProperty(std::string const& prop, cmValue value);
void SetProperty(std::string const& prop, std::nullptr_t) void SetProperty(std::string const& prop, std::nullptr_t)
@@ -232,6 +234,7 @@ public:
bool IsForeign() const; bool IsForeign() const;
bool IsPerConfig() const; bool IsPerConfig() const;
bool IsRuntimeBinary() const; bool IsRuntimeBinary() const;
bool IsSymbolic() const;
bool CanCompileSources() const; bool CanCompileSources() const;
bool GetMappedConfig(std::string const& desiredConfig, cmValue& loc, bool GetMappedConfig(std::string const& desiredConfig, cmValue& loc,

View File

@@ -102,6 +102,11 @@ bool cmTargetLinkLibrariesCommand(std::vector<std::string> const& args,
return true; return true;
} }
if (target->IsSymbolic()) {
status.SetError("can not be used on a SYMBOLIC target.");
return false;
}
// Having a UTILITY library on the LHS is a bug. // Having a UTILITY library on the LHS is a bug.
if (target->GetType() == cmStateEnums::UTILITY) { if (target->GetType() == cmStateEnums::UTILITY) {
mf.IssueMessage( mf.IssueMessage(

View File

@@ -42,6 +42,10 @@ bool cmTargetPropCommandBase::HandleArguments(
this->HandleMissingTarget(args[0]); this->HandleMissingTarget(args[0]);
return false; return false;
} }
if (this->Target->IsSymbolic()) {
this->SetError("can not be used on a SYMBOLIC target.");
return false;
}
bool const isRegularTarget = bool const isRegularTarget =
(this->Target->GetType() == cmStateEnums::EXECUTABLE) || (this->Target->GetType() == cmStateEnums::EXECUTABLE) ||
(this->Target->GetType() == cmStateEnums::STATIC_LIBRARY) || (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY) ||

View File

@@ -0,0 +1,5 @@
add_library(gui INTERFACE)
add_library(widget INTERFACE SYMBOLIC)
install(TARGETS gui widget EXPORT gui-targets)
install(EXPORT gui-targets DESTINATION lib/cmake/gui FILE gui-config.cmake NAMESPACE gui::)

View File

@@ -0,0 +1,6 @@
enable_language(C)
find_package(gui REQUIRED)
add_library(baz INTERFACE)
target_link_libraries(baz INTERFACE gui::gui gui::widget)

View File

@@ -18,11 +18,14 @@ function(run_ExportImport_test case)
run_cmake_with_options(${case}-import run_cmake_with_options(${case}-import
-Dfoo_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/foo -Dfoo_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/foo
-Dbar_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/bar -Dbar_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/bar
-Dgui_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/gui
) )
endfunction() endfunction()
run_ExportImport_test(SharedDep) run_ExportImport_test(SharedDep)
run_ExportImport_test(SpdxLicenseProperty) run_ExportImport_test(SpdxLicenseProperty)
run_ExportImport_test(InterfaceWithSymbolic)
function(run_ExportImportBuildInstall_test case) function(run_ExportImportBuildInstall_test case)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-export-build) set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-export-build)

View File

@@ -0,0 +1,7 @@
include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
set(out_dir "${RunCMake_BINARY_DIR}/ExportSymbolicComponent-build")
file(READ "${out_dir}/foo.cps" content)
expect_value("${content}" "foo" "name")
expect_value("${content}" "symbolic" "components" "foo" "type")

View File

@@ -0,0 +1,4 @@
add_library(foo INTERFACE SYMBOLIC)
install(TARGETS foo EXPORT foo DESTINATION .)
export(EXPORT foo PACKAGE_INFO foo)

View File

@@ -38,6 +38,7 @@ run_cmake(Minimal)
run_cmake(MinimalVersion) run_cmake(MinimalVersion)
run_cmake(LowerCaseFile) run_cmake(LowerCaseFile)
run_cmake(Requirements) run_cmake(Requirements)
run_cmake(ExportSymbolicComponent)
run_cmake(TargetTypes) run_cmake(TargetTypes)
run_cmake(DependsMultiple) run_cmake(DependsMultiple)
run_cmake(LinkOnly) run_cmake(LinkOnly)
@@ -46,3 +47,4 @@ run_cmake(EmptyConfig)
run_cmake(FileSetHeaders) run_cmake(FileSetHeaders)
run_cmake(DependencyVersionCMake) run_cmake(DependencyVersionCMake)
run_cmake(DependencyVersionCps) run_cmake(DependencyVersionCps)
run_cmake(TransitiveSymbolicComponent)

View File

@@ -0,0 +1,16 @@
include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
set(out_dir "${RunCMake_BINARY_DIR}/TransitiveSymbolicComponent-build")
file(READ "${out_dir}/bar.cps" content)
expect_value("${content}" "bar" "name")
expect_array("${content}" 1 "requires" "Symbolic" "components")
expect_value("${content}" "test" "requires" "Symbolic" "components" 0)
expect_value("${content}" "1.0" "requires" "Symbolic" "version")
expect_array("${content}" 1 "requires" "Symbolic" "hints")
expect_value("${content}" "${CMAKE_CURRENT_LIST_DIR}/cps" "requires" "Symbolic" "hints" 0)
string(JSON component GET "${content}" "components" "bar")
expect_array("${component}" 1 "requires")
expect_value("${component}" "Symbolic:test" "requires" 0)

View File

@@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 4.0)
add_library(bar INTERFACE)
find_package(Symbolic REQUIRED CONFIG
COMPONENTS foo test
NO_DEFAULT_PATH
PATHS ${CMAKE_CURRENT_LIST_DIR}
)
target_link_libraries(bar INTERFACE Symbolic::test)
install(TARGETS bar EXPORT bar DESTINATION .)
export(EXPORT bar PACKAGE_INFO bar)

View File

@@ -0,0 +1,17 @@
{
"components" :
{
"foo" :
{
"type" : "interface"
},
"test" :
{
"type" : "symbolic"
}
},
"cps_path" : "@prefix@",
"cps_version" : "0.13.0",
"name" : "Symbolic",
"version": "1.0"
}

View File

@@ -0,0 +1,7 @@
include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
set(out_dir "${RunCMake_BINARY_DIR}/InstallSymbolicComponent-build/CMakeFiles/Export/5058f1af8388633f609cadb75a75dc9d")
file(READ "${out_dir}/foo.cps" content)
expect_value("${content}" "foo" "name")
expect_value("${content}" "symbolic" "components" "foo" "type")

View File

@@ -0,0 +1,4 @@
add_library(foo INTERFACE SYMBOLIC)
install(TARGETS foo EXPORT foo)
install(PACKAGE_INFO foo EXPORT foo DESTINATION .)

View File

@@ -55,4 +55,6 @@ run_cmake(EmptyConfig)
run_cmake(FileSetHeaders) run_cmake(FileSetHeaders)
run_cmake(DependencyVersionCMake) run_cmake(DependencyVersionCMake)
run_cmake(DependencyVersionCps) run_cmake(DependencyVersionCps)
run_cmake(TransitiveSymbolicComponent)
run_cmake(InstallSymbolicComponent)
run_cmake_install(Destination) run_cmake_install(Destination)

View File

@@ -0,0 +1,15 @@
include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
set(out_dir "${RunCMake_BINARY_DIR}/TransitiveSymbolicComponent-build/CMakeFiles/Export/5058f1af8388633f609cadb75a75dc9d")
file(READ "${out_dir}/bar.cps" content)
expect_value("${content}" "bar" "name")
expect_array("${content}" 1 "requires" "Symbolic" "components")
expect_value("${content}" "test" "requires" "Symbolic" "components" 0)
expect_value("${content}" "1.0" "requires" "Symbolic" "version")
expect_array("${content}" 1 "requires" "Symbolic" "hints")
expect_value("${content}" "${CMAKE_CURRENT_LIST_DIR}/cps" "requires" "Symbolic" "hints" 0)
string(JSON component GET "${content}" "components" "bar")
expect_array("${component}" 1 "requires")
expect_value("${component}" "Symbolic:test" "requires" 0)

View File

@@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 4.0)
add_library(bar INTERFACE)
find_package(Symbolic REQUIRED CONFIG
COMPONENTS foo test
NO_DEFAULT_PATH
PATHS ${CMAKE_CURRENT_LIST_DIR}
)
target_link_libraries(bar INTERFACE Symbolic::test)
install(TARGETS bar EXPORT bar)
install(PACKAGE_INFO bar EXPORT bar DESTINATION .)

View File

@@ -0,0 +1,17 @@
{
"components" :
{
"foo" :
{
"type" : "interface"
},
"test" :
{
"type" : "symbolic"
}
},
"cps_path" : "@prefix@",
"cps_version" : "0.13.0",
"name" : "Symbolic",
"version": "1.0"
}

View File

@@ -0,0 +1,8 @@
add_library(TestSymbolicInterfaceLib INTERFACE SYMBOLIC)
get_target_property(IS_SYMBOLIC TestSymbolicInterfaceLib "SYMBOLIC")
if("${IS_SYMBOLIC}" STREQUAL "FALSE")
string(APPEND RunCMake_TEST_FAILED "Target: \"TestSymbolicInterfaceLib\" does not have the SYMBOLIC property")
set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
endif()

View File

@@ -3,6 +3,7 @@ include(RunCMake)
run_cmake(CMP0073) run_cmake(CMP0073)
run_cmake(INTERFACEwithNoSources) run_cmake(INTERFACEwithNoSources)
run_cmake(INTERFACEwithSYMBOLIC)
run_cmake(OBJECTwithNoSources) run_cmake(OBJECTwithNoSources)
run_cmake(STATICwithNoSources) run_cmake(STATICwithNoSources)
run_cmake(SHAREDwithNoSources) run_cmake(SHAREDwithNoSources)
@@ -19,6 +20,7 @@ run_cmake(UNKNOWNwithOnlyObjectSources)
run_cmake(INTERFACEwithNoSourcesButLinkObjects) run_cmake(INTERFACEwithNoSourcesButLinkObjects)
run_cmake(OBJECTwithNoSourcesButLinkObjects) run_cmake(OBJECTwithNoSourcesButLinkObjects)
run_cmake(STATICwithNoSourcesButLinkObjects) run_cmake(STATICwithNoSourcesButLinkObjects)
run_cmake(STATICwithSYMBOLIC)
run_cmake(SHAREDwithNoSourcesButLinkObjects) run_cmake(SHAREDwithNoSourcesButLinkObjects)
run_cmake(MODULEwithNoSourcesButLinkObjects) run_cmake(MODULEwithNoSourcesButLinkObjects)
run_cmake(UNKNOWNwithNoSourcesButLinkObjects) run_cmake(UNKNOWNwithNoSourcesButLinkObjects)

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,4 @@
^CMake Error at STATICwithSYMBOLIC.cmake:[0-9]+ \(add_library\):
add_library SYMBOLIC option may only be used with INTERFACE libraries
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)$

View File

@@ -0,0 +1 @@
add_library(TestStaticWithSymbolic STATIC SYMBOLIC)

View File

@@ -27,3 +27,4 @@ run_cmake(FindDependencyExportStatic)
run_cmake(FindDependencyExportShared) run_cmake(FindDependencyExportShared)
#FIXME(#26622): The FindDependencyExportFetchContent test case exposes an assertion failure. #FIXME(#26622): The FindDependencyExportFetchContent test case exposes an assertion failure.
#run_cmake(FindDependencyExportFetchContent) #run_cmake(FindDependencyExportFetchContent)
run_cmake(SymbolicComponent)

View File

@@ -0,0 +1,4 @@
file(READ "${RunCMake_TEST_BINARY_DIR}/foo.cmake" foo)
if("${foo}" MATCHES "add_library\(foo INTERFACE SYMBOLIC IMPORTED\)")
string(APPEND RunCMake_TEST_FAILED "Symbolic Component Foo was not exported\n")
endif()

View File

@@ -0,0 +1,2 @@
add_library(foo INTERFACE SYMBOLIC)
export(TARGETS foo FILE foo.cmake)

View File

@@ -54,9 +54,4 @@ run_cmake(MissingComponentDependency)
run_cmake(MissingTransitiveComponentCPS) run_cmake(MissingTransitiveComponentCPS)
run_cmake(MissingTransitiveComponentCMake) run_cmake(MissingTransitiveComponentCMake)
run_cmake(MissingTransitiveComponentDependency) run_cmake(MissingTransitiveComponentDependency)
run_cmake(SymbolicComponents)
# Configuration selection tests
run_cmake_build(ConfigDefault)
run_cmake_build(ConfigFirst)
run_cmake_build(ConfigMapped)
run_cmake_build(ConfigMatchBuildType Test)

View File

@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 4.0)
include(Setup.cmake)
add_library(bar INTERFACE)
find_package(Symbolic REQUIRED COMPONENTS foo test)
target_link_libraries(bar INTERFACE Symbolic::foo Symbolic::test)

View File

@@ -0,0 +1,17 @@
{
"components" :
{
"foo" :
{
"type" : "interface"
},
"test" :
{
"type" : "symbolic"
}
},
"cps_path" : "@prefix@",
"cps_version" : "0.13.0",
"name" : "Symbolic",
"version": "1.0"
}

View File

@@ -97,7 +97,7 @@ foreach(policy IN ITEMS NEW OLD WARN)
run_install_test(CMP0177-${policy}) run_install_test(CMP0177-${policy})
run_cmake_with_options(CMP0177-${policy}-verify run_cmake_with_options(CMP0177-${policy}-verify
-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/CMP0177-${policy}-build/root-all -DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/CMP0177-${policy}-build/root-all
) )
endforeach() endforeach()
run_cmake(TARGETS-ImportedGlobal) run_cmake(TARGETS-ImportedGlobal)
run_cmake(TARGETS-NAMELINK_COMPONENT-bad-all) run_cmake(TARGETS-NAMELINK_COMPONENT-bad-all)
@@ -106,7 +106,7 @@ run_cmake(FILES-DESTINATION-TYPE)
run_cmake(DIRECTORY-DESTINATION-TYPE) run_cmake(DIRECTORY-DESTINATION-TYPE)
run_cmake(FILES-directory) run_cmake(FILES-directory)
if(NOT WIN32) if(NOT WIN32)
run_cmake(FILES-symlink-to-directory) run_cmake(FILES-symlink-to-directory)
endif() endif()
set(RunCMake_TEST_OPTIONS "-DCMAKE_BUILD_TYPE:STRING=Debug") set(RunCMake_TEST_OPTIONS "-DCMAKE_BUILD_TYPE:STRING=Debug")
@@ -131,6 +131,7 @@ run_install_test(TARGETS-OPTIONAL)
run_install_test(FILES-OPTIONAL) run_install_test(FILES-OPTIONAL)
run_install_test(DIRECTORY-OPTIONAL) run_install_test(DIRECTORY-OPTIONAL)
run_install_test(TARGETS-Defaults) run_install_test(TARGETS-Defaults)
run_install_test(TARGETS-SymbolicComponent)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux") if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
run_install_test(TARGETS-NAMELINK-No-Tweak) run_install_test(TARGETS-NAMELINK-No-Tweak)

View File

@@ -0,0 +1,5 @@
file(READ "${RunCMake_TEST_BINARY_DIR}/root-all/foo.cmake" foo)
if("${foo}" MATCHES "add_library\(foo INTERFACE SYMBOLIC IMPORTED\)")
string(APPEND RunCMake_TEST_FAILED "Symbolic Component Foo was not exported\n")
endif()

View File

@@ -0,0 +1,3 @@
add_library(foo INTERFACE SYMBOLIC)
install(TARGETS foo EXPORT foo)
install(EXPORT foo DESTINATION . FILE foo.cmake)