diff --git a/Help/command/add_library.rst b/Help/command/add_library.rst index 50cb0bcb8c..66ce32717f 100644 --- a/Help/command/add_library.rst +++ b/Help/command/add_library.rst @@ -196,6 +196,30 @@ Interface Libraries call are ``PRIVATE`` to the interface library and do not appear in its :prop_tgt:`INTERFACE_SOURCES` target property. +.. signature:: + add_library( INTERFACE SYMBOLIC) + :target: INTERFACE-SYMBOLIC + + .. versionadded:: 4.2 + + Add a symbolic :ref:`Interface Library ` 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`: Imported Libraries diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 0d87a716f2..947b1affeb 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -417,6 +417,7 @@ Properties on Targets /prop_tgt/Swift_LANGUAGE_VERSION /prop_tgt/Swift_MODULE_DIRECTORY /prop_tgt/Swift_MODULE_NAME + /prop_tgt/SYMBOLIC /prop_tgt/SYSTEM /prop_tgt/TEST_LAUNCHER /prop_tgt/TRANSITIVE_COMPILE_PROPERTIES diff --git a/Help/prop_tgt/SYMBOLIC.rst b/Help/prop_tgt/SYMBOLIC.rst new file mode 100644 index 0000000000..36ebe6b334 --- /dev/null +++ b/Help/prop_tgt/SYMBOLIC.rst @@ -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) `. +They are useful for packages to represent additional **components** or +**feature selectors** that consumers can request via ``find_package()``. diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx index 842eb3be35..1c9d0c6d19 100644 --- a/Source/cmAddLibraryCommand.cxx +++ b/Source/cmAddLibraryCommand.cxx @@ -33,6 +33,7 @@ bool cmAddLibraryCommand(std::vector const& args, bool excludeFromAll = false; bool importTarget = false; bool importGlobal = false; + bool symbolicTarget = false; auto s = args.begin(); @@ -117,6 +118,9 @@ bool cmAddLibraryCommand(std::vector const& args, } else if (*s == "EXCLUDE_FROM_ALL") { ++s; excludeFromAll = true; + } else if (*s == "SYMBOLIC") { + ++s; + symbolicTarget = true; } else if (*s == "IMPORTED") { ++s; importTarget = true; @@ -223,9 +227,9 @@ bool cmAddLibraryCommand(std::vector const& args, } /* ideally we should check whether for the linker language of the target - 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 - yet its linker language. */ + 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 + yet its linker language. */ if ((type == cmStateEnums::SHARED_LIBRARY || type == cmStateEnums::MODULE_LIBRARY) && !mf.GetState()->GetGlobalPropertyAsBool("TARGET_SUPPORTS_SHARED_LIBS")) { @@ -282,7 +286,8 @@ bool cmAddLibraryCommand(std::vector const& args, } // Create the imported target. - mf.AddImportedTarget(libName, type, importGlobal); + cmTarget* target = mf.AddImportedTarget(libName, type, importGlobal); + target->SetSymbolic(symbolicTarget); return true; } @@ -312,8 +317,15 @@ bool cmAddLibraryCommand(std::vector const& args, } } + if (symbolicTarget && type != cmStateEnums::INTERFACE_LIBRARY) { + status.SetError( + "SYMBOLIC option may only be used with INTERFACE libraries"); + return false; + } + std::vector srcs(s, args.end()); - mf.AddLibrary(libName, type, srcs, excludeFromAll); + cmTarget* target = mf.AddLibrary(libName, type, srcs, excludeFromAll); + target->SetSymbolic(symbolicTarget); return true; } diff --git a/Source/cmExportCMakeConfigGenerator.cxx b/Source/cmExportCMakeConfigGenerator.cxx index f0980b4c34..d9be54ecfe 100644 --- a/Source/cmExportCMakeConfigGenerator.cxx +++ b/Source/cmExportCMakeConfigGenerator.cxx @@ -292,7 +292,20 @@ void cmExportCMakeConfigGenerator::GenerateImportTargetCode( os << "add_library(" << targetName << " OBJECT IMPORTED)\n"; break; 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; default: // should never happen break; diff --git a/Source/cmExportPackageInfoGenerator.cxx b/Source/cmExportPackageInfoGenerator.cxx index 4b17ac25d5..47195306ee 100644 --- a/Source/cmExportPackageInfoGenerator.cxx +++ b/Source/cmExportPackageInfoGenerator.cxx @@ -182,6 +182,7 @@ Json::Value* cmExportPackageInfoGenerator::GenerateImportTarget( Json::Value& component = components[name]; Json::Value& type = component["type"]; + switch (targetType) { case cmStateEnums::EXECUTABLE: type = "executable"; @@ -196,7 +197,7 @@ Json::Value* cmExportPackageInfoGenerator::GenerateImportTarget( type = "module"; break; case cmStateEnums::INTERFACE_LIBRARY: - type = "interface"; + type = target->IsSymbolic() ? "symbolic" : "interface"; break; default: type = "unknown"; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index b74cfcaeac..b437dcef66 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -1153,6 +1153,11 @@ bool cmGeneratorTarget::IsImportedGloballyVisible() const return this->Target->IsImportedGloballyVisible(); } +bool cmGeneratorTarget::IsSymbolic() const +{ + return this->Target->IsSymbolic(); +} + bool cmGeneratorTarget::IsForeign() const { return this->Target->IsForeign(); diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index f8116f74e2..5b39d01915 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -70,6 +70,7 @@ public: bool IsImported() const; bool IsImportedGloballyVisible() const; bool IsForeign() const; + bool IsSymbolic() const; bool CanCompileSources() const; bool HasKnownRuntimeArtifactLocation(std::string const& config) const; std::string const& GetLocation(std::string const& config) const; diff --git a/Source/cmPackageInfoReader.cxx b/Source/cmPackageInfoReader.cxx index 66e112e271..dace12167b 100644 --- a/Source/cmPackageInfoReader.cxx +++ b/Source/cmPackageInfoReader.cxx @@ -773,7 +773,9 @@ bool cmPackageInfoReader::ImportTargets(cmMakefile* makefile, cmTarget* target = nullptr; if (type == "symbolic"_s) { - // TODO + target = this->AddLibraryComponent( + makefile, cmStateEnums::INTERFACE_LIBRARY, fullName, *ci, package); + target->SetSymbolic(true); } else if (type == "dylib"_s) { target = this->AddLibraryComponent( makefile, cmStateEnums::SHARED_LIBRARY, fullName, *ci, package); diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx index 4f18997712..f10fe5ad53 100644 --- a/Source/cmSetPropertyCommand.cxx +++ b/Source/cmSetPropertyCommand.cxx @@ -634,7 +634,13 @@ bool HandleTargetMode(cmExecutionStatus& status, status.SetError("can not be used on an ALIAS target."); return false; } + 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. if (!HandleTarget(target, status.GetMakefile(), propertyName, propertyValue, appendAsString, appendMode, remove)) { diff --git a/Source/cmSetTargetPropertiesCommand.cxx b/Source/cmSetTargetPropertiesCommand.cxx index 64be3be1e7..0009bd2d50 100644 --- a/Source/cmSetTargetPropertiesCommand.cxx +++ b/Source/cmSetTargetPropertiesCommand.cxx @@ -40,6 +40,10 @@ bool cmSetTargetPropertiesCommand(std::vector const& args, return false; } 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 for (auto k = propsIter + 1; k != args.end(); k += 2) { target->SetProperty(*k, *(k + 1)); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index b8f1f6ff73..6c0cd8b6cc 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -608,6 +608,7 @@ public: bool IsAndroid; bool BuildInterfaceIncludesAppended; bool PerConfig; + bool IsSymbolic; cmTarget::Visibility TargetVisibility; std::set>> Utilities; std::set CodegenDependencies; @@ -885,6 +886,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->impl->IsAIX = false; this->impl->IsApple = false; this->impl->IsAndroid = false; + this->impl->IsSymbolic = false; this->impl->TargetVisibility = vis; this->impl->BuildInterfaceIncludesAppended = false; this->impl->PerConfig = (perConfig == PerConfig::Yes); @@ -1946,6 +1948,7 @@ MAKE_PROP(LINK_LIBRARIES); MAKE_PROP(MANUALLY_ADDED_DEPENDENCIES); MAKE_PROP(NAME); MAKE_PROP(SOURCES); +MAKE_PROP(SYMBOLIC); MAKE_PROP(TYPE); MAKE_PROP(BINARY_DIR); MAKE_PROP(SOURCE_DIR); @@ -2047,6 +2050,7 @@ bool IsSettableProperty(cmMakefile* context, cmTarget* target, { "MANUALLY_ADDED_DEPENDENCIES", { ROC::All } }, { "NAME", { ROC::All } }, { "SOURCES", { ROC::Imported } }, + { "SYMBOLIC", { ROC::All } }, { "TYPE", { ROC::All } }, { "ALIAS_GLOBAL", { 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) { if (!IsSettableProperty(this->impl->Makefile, this, prop)) { @@ -2606,6 +2615,7 @@ cmValue cmTarget::GetProperty(std::string const& prop) const propBINARY_DIR, propSOURCE_DIR, propSOURCES, + propSYMBOLIC, propINTERFACE_LINK_LIBRARIES, propINTERFACE_LINK_LIBRARIES_DIRECT, propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE, @@ -2626,6 +2636,10 @@ cmValue cmTarget::GetProperty(std::string const& prop) const return cmValue(propertyIter->second.Value); } + if (prop == propSYMBOLIC) { + return this->IsSymbolic() ? cmValue(propTRUE) : cmValue(propFALSE); + } + UsageRequirementProperty const* usageRequirements[] = { &this->impl->IncludeDirectories, &this->impl->CompileOptions, @@ -2760,6 +2774,11 @@ bool cmTarget::IsApple() const return this->impl->IsApple; } +bool cmTarget::IsSymbolic() const +{ + return this->impl->IsSymbolic; +} + bool cmTarget::IsNormal() const { switch (this->impl->TargetVisibility) { diff --git a/Source/cmTarget.h b/Source/cmTarget.h index f9388fead3..474597e9b3 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -193,6 +193,8 @@ public: //! Get the utilities used by this target std::set>> const& GetUtilities() const; + void SetSymbolic(bool value); + //! Set/Get a property of this target file void SetProperty(std::string const& prop, cmValue value); void SetProperty(std::string const& prop, std::nullptr_t) @@ -232,6 +234,7 @@ public: bool IsForeign() const; bool IsPerConfig() const; bool IsRuntimeBinary() const; + bool IsSymbolic() const; bool CanCompileSources() const; bool GetMappedConfig(std::string const& desiredConfig, cmValue& loc, diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index 275fa7655a..0d6cb7cb34 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -102,6 +102,11 @@ bool cmTargetLinkLibrariesCommand(std::vector const& args, 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. if (target->GetType() == cmStateEnums::UTILITY) { mf.IssueMessage( diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx index 9b9a7089d1..960e36cf40 100644 --- a/Source/cmTargetPropCommandBase.cxx +++ b/Source/cmTargetPropCommandBase.cxx @@ -42,6 +42,10 @@ bool cmTargetPropCommandBase::HandleArguments( this->HandleMissingTarget(args[0]); return false; } + if (this->Target->IsSymbolic()) { + this->SetError("can not be used on a SYMBOLIC target."); + return false; + } bool const isRegularTarget = (this->Target->GetType() == cmStateEnums::EXECUTABLE) || (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY) || diff --git a/Tests/RunCMake/ExportImport/InterfaceWithSymbolic-export.cmake b/Tests/RunCMake/ExportImport/InterfaceWithSymbolic-export.cmake new file mode 100644 index 0000000000..e41c5a937e --- /dev/null +++ b/Tests/RunCMake/ExportImport/InterfaceWithSymbolic-export.cmake @@ -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::) diff --git a/Tests/RunCMake/ExportImport/InterfaceWithSymbolic-import.cmake b/Tests/RunCMake/ExportImport/InterfaceWithSymbolic-import.cmake new file mode 100644 index 0000000000..f2baab2f24 --- /dev/null +++ b/Tests/RunCMake/ExportImport/InterfaceWithSymbolic-import.cmake @@ -0,0 +1,6 @@ +enable_language(C) +find_package(gui REQUIRED) + +add_library(baz INTERFACE) + +target_link_libraries(baz INTERFACE gui::gui gui::widget) diff --git a/Tests/RunCMake/ExportImport/RunCMakeTest.cmake b/Tests/RunCMake/ExportImport/RunCMakeTest.cmake index 9bc6f76515..e404e83453 100644 --- a/Tests/RunCMake/ExportImport/RunCMakeTest.cmake +++ b/Tests/RunCMake/ExportImport/RunCMakeTest.cmake @@ -18,11 +18,14 @@ function(run_ExportImport_test case) run_cmake_with_options(${case}-import -Dfoo_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/foo -Dbar_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/bar + -Dgui_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/gui ) endfunction() run_ExportImport_test(SharedDep) run_ExportImport_test(SpdxLicenseProperty) +run_ExportImport_test(InterfaceWithSymbolic) + function(run_ExportImportBuildInstall_test case) set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-export-build) diff --git a/Tests/RunCMake/ExportPackageInfo/ExportSymbolicComponent-check.cmake b/Tests/RunCMake/ExportPackageInfo/ExportSymbolicComponent-check.cmake new file mode 100644 index 0000000000..4aa44efa6b --- /dev/null +++ b/Tests/RunCMake/ExportPackageInfo/ExportSymbolicComponent-check.cmake @@ -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") diff --git a/Tests/RunCMake/ExportPackageInfo/ExportSymbolicComponent.cmake b/Tests/RunCMake/ExportPackageInfo/ExportSymbolicComponent.cmake new file mode 100644 index 0000000000..d24caeb2f2 --- /dev/null +++ b/Tests/RunCMake/ExportPackageInfo/ExportSymbolicComponent.cmake @@ -0,0 +1,4 @@ +add_library(foo INTERFACE SYMBOLIC) + +install(TARGETS foo EXPORT foo DESTINATION .) +export(EXPORT foo PACKAGE_INFO foo) diff --git a/Tests/RunCMake/ExportPackageInfo/RunCMakeTest.cmake b/Tests/RunCMake/ExportPackageInfo/RunCMakeTest.cmake index 45c4397e5d..b38ef80cc3 100644 --- a/Tests/RunCMake/ExportPackageInfo/RunCMakeTest.cmake +++ b/Tests/RunCMake/ExportPackageInfo/RunCMakeTest.cmake @@ -38,6 +38,7 @@ run_cmake(Minimal) run_cmake(MinimalVersion) run_cmake(LowerCaseFile) run_cmake(Requirements) +run_cmake(ExportSymbolicComponent) run_cmake(TargetTypes) run_cmake(DependsMultiple) run_cmake(LinkOnly) @@ -46,3 +47,4 @@ run_cmake(EmptyConfig) run_cmake(FileSetHeaders) run_cmake(DependencyVersionCMake) run_cmake(DependencyVersionCps) +run_cmake(TransitiveSymbolicComponent) diff --git a/Tests/RunCMake/ExportPackageInfo/TransitiveSymbolicComponent-check.cmake b/Tests/RunCMake/ExportPackageInfo/TransitiveSymbolicComponent-check.cmake new file mode 100644 index 0000000000..fbadeb82b0 --- /dev/null +++ b/Tests/RunCMake/ExportPackageInfo/TransitiveSymbolicComponent-check.cmake @@ -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) diff --git a/Tests/RunCMake/ExportPackageInfo/TransitiveSymbolicComponent.cmake b/Tests/RunCMake/ExportPackageInfo/TransitiveSymbolicComponent.cmake new file mode 100644 index 0000000000..cf3cad1107 --- /dev/null +++ b/Tests/RunCMake/ExportPackageInfo/TransitiveSymbolicComponent.cmake @@ -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) diff --git a/Tests/RunCMake/ExportPackageInfo/cps/symbolic.cps b/Tests/RunCMake/ExportPackageInfo/cps/symbolic.cps new file mode 100644 index 0000000000..e5c2e29f18 --- /dev/null +++ b/Tests/RunCMake/ExportPackageInfo/cps/symbolic.cps @@ -0,0 +1,17 @@ +{ + "components" : + { + "foo" : + { + "type" : "interface" + }, + "test" : + { + "type" : "symbolic" + } + }, + "cps_path" : "@prefix@", + "cps_version" : "0.13.0", + "name" : "Symbolic", + "version": "1.0" +} diff --git a/Tests/RunCMake/InstallPackageInfo/InstallSymbolicComponent-check.cmake b/Tests/RunCMake/InstallPackageInfo/InstallSymbolicComponent-check.cmake new file mode 100644 index 0000000000..ec5624c2e7 --- /dev/null +++ b/Tests/RunCMake/InstallPackageInfo/InstallSymbolicComponent-check.cmake @@ -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") diff --git a/Tests/RunCMake/InstallPackageInfo/InstallSymbolicComponent.cmake b/Tests/RunCMake/InstallPackageInfo/InstallSymbolicComponent.cmake new file mode 100644 index 0000000000..a4dc594742 --- /dev/null +++ b/Tests/RunCMake/InstallPackageInfo/InstallSymbolicComponent.cmake @@ -0,0 +1,4 @@ +add_library(foo INTERFACE SYMBOLIC) + +install(TARGETS foo EXPORT foo) +install(PACKAGE_INFO foo EXPORT foo DESTINATION .) diff --git a/Tests/RunCMake/InstallPackageInfo/RunCMakeTest.cmake b/Tests/RunCMake/InstallPackageInfo/RunCMakeTest.cmake index 475394218f..9608f6b927 100644 --- a/Tests/RunCMake/InstallPackageInfo/RunCMakeTest.cmake +++ b/Tests/RunCMake/InstallPackageInfo/RunCMakeTest.cmake @@ -55,4 +55,6 @@ run_cmake(EmptyConfig) run_cmake(FileSetHeaders) run_cmake(DependencyVersionCMake) run_cmake(DependencyVersionCps) +run_cmake(TransitiveSymbolicComponent) +run_cmake(InstallSymbolicComponent) run_cmake_install(Destination) diff --git a/Tests/RunCMake/InstallPackageInfo/TransitiveSymbolicComponent-check.cmake b/Tests/RunCMake/InstallPackageInfo/TransitiveSymbolicComponent-check.cmake new file mode 100644 index 0000000000..6fd9ae14da --- /dev/null +++ b/Tests/RunCMake/InstallPackageInfo/TransitiveSymbolicComponent-check.cmake @@ -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) diff --git a/Tests/RunCMake/InstallPackageInfo/TransitiveSymbolicComponent.cmake b/Tests/RunCMake/InstallPackageInfo/TransitiveSymbolicComponent.cmake new file mode 100644 index 0000000000..d1ccc75350 --- /dev/null +++ b/Tests/RunCMake/InstallPackageInfo/TransitiveSymbolicComponent.cmake @@ -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 .) diff --git a/Tests/RunCMake/InstallPackageInfo/cps/symbolic.cps b/Tests/RunCMake/InstallPackageInfo/cps/symbolic.cps new file mode 100644 index 0000000000..e5c2e29f18 --- /dev/null +++ b/Tests/RunCMake/InstallPackageInfo/cps/symbolic.cps @@ -0,0 +1,17 @@ +{ + "components" : + { + "foo" : + { + "type" : "interface" + }, + "test" : + { + "type" : "symbolic" + } + }, + "cps_path" : "@prefix@", + "cps_version" : "0.13.0", + "name" : "Symbolic", + "version": "1.0" +} diff --git a/Tests/RunCMake/add_library/INTERFACEwithSYMBOLIC.cmake b/Tests/RunCMake/add_library/INTERFACEwithSYMBOLIC.cmake new file mode 100644 index 0000000000..08370e14de --- /dev/null +++ b/Tests/RunCMake/add_library/INTERFACEwithSYMBOLIC.cmake @@ -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() diff --git a/Tests/RunCMake/add_library/RunCMakeTest.cmake b/Tests/RunCMake/add_library/RunCMakeTest.cmake index 26b94f80b2..318a528738 100644 --- a/Tests/RunCMake/add_library/RunCMakeTest.cmake +++ b/Tests/RunCMake/add_library/RunCMakeTest.cmake @@ -3,6 +3,7 @@ include(RunCMake) run_cmake(CMP0073) run_cmake(INTERFACEwithNoSources) +run_cmake(INTERFACEwithSYMBOLIC) run_cmake(OBJECTwithNoSources) run_cmake(STATICwithNoSources) run_cmake(SHAREDwithNoSources) @@ -19,6 +20,7 @@ run_cmake(UNKNOWNwithOnlyObjectSources) run_cmake(INTERFACEwithNoSourcesButLinkObjects) run_cmake(OBJECTwithNoSourcesButLinkObjects) run_cmake(STATICwithNoSourcesButLinkObjects) +run_cmake(STATICwithSYMBOLIC) run_cmake(SHAREDwithNoSourcesButLinkObjects) run_cmake(MODULEwithNoSourcesButLinkObjects) run_cmake(UNKNOWNwithNoSourcesButLinkObjects) diff --git a/Tests/RunCMake/add_library/STATICwithSYMBOLIC-result.txt b/Tests/RunCMake/add_library/STATICwithSYMBOLIC-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/add_library/STATICwithSYMBOLIC-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/add_library/STATICwithSYMBOLIC-stderr.txt b/Tests/RunCMake/add_library/STATICwithSYMBOLIC-stderr.txt new file mode 100644 index 0000000000..16a4792c66 --- /dev/null +++ b/Tests/RunCMake/add_library/STATICwithSYMBOLIC-stderr.txt @@ -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\)$ diff --git a/Tests/RunCMake/add_library/STATICwithSYMBOLIC.cmake b/Tests/RunCMake/add_library/STATICwithSYMBOLIC.cmake new file mode 100644 index 0000000000..537df7964d --- /dev/null +++ b/Tests/RunCMake/add_library/STATICwithSYMBOLIC.cmake @@ -0,0 +1 @@ +add_library(TestStaticWithSymbolic STATIC SYMBOLIC) diff --git a/Tests/RunCMake/export/RunCMakeTest.cmake b/Tests/RunCMake/export/RunCMakeTest.cmake index 8dcea7f7ef..a638f92358 100644 --- a/Tests/RunCMake/export/RunCMakeTest.cmake +++ b/Tests/RunCMake/export/RunCMakeTest.cmake @@ -27,3 +27,4 @@ run_cmake(FindDependencyExportStatic) run_cmake(FindDependencyExportShared) #FIXME(#26622): The FindDependencyExportFetchContent test case exposes an assertion failure. #run_cmake(FindDependencyExportFetchContent) +run_cmake(SymbolicComponent) diff --git a/Tests/RunCMake/export/SymbolicComponent-check.cmake b/Tests/RunCMake/export/SymbolicComponent-check.cmake new file mode 100644 index 0000000000..43d96fc710 --- /dev/null +++ b/Tests/RunCMake/export/SymbolicComponent-check.cmake @@ -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() diff --git a/Tests/RunCMake/export/SymbolicComponent.cmake b/Tests/RunCMake/export/SymbolicComponent.cmake new file mode 100644 index 0000000000..c0189c9492 --- /dev/null +++ b/Tests/RunCMake/export/SymbolicComponent.cmake @@ -0,0 +1,2 @@ +add_library(foo INTERFACE SYMBOLIC) +export(TARGETS foo FILE foo.cmake) diff --git a/Tests/RunCMake/find_package-CPS/RunCMakeTest.cmake b/Tests/RunCMake/find_package-CPS/RunCMakeTest.cmake index ff8aeac8ca..b6749f7b19 100644 --- a/Tests/RunCMake/find_package-CPS/RunCMakeTest.cmake +++ b/Tests/RunCMake/find_package-CPS/RunCMakeTest.cmake @@ -54,9 +54,4 @@ run_cmake(MissingComponentDependency) run_cmake(MissingTransitiveComponentCPS) run_cmake(MissingTransitiveComponentCMake) run_cmake(MissingTransitiveComponentDependency) - -# Configuration selection tests -run_cmake_build(ConfigDefault) -run_cmake_build(ConfigFirst) -run_cmake_build(ConfigMapped) -run_cmake_build(ConfigMatchBuildType Test) +run_cmake(SymbolicComponents) diff --git a/Tests/RunCMake/find_package-CPS/SymbolicComponents.cmake b/Tests/RunCMake/find_package-CPS/SymbolicComponents.cmake new file mode 100644 index 0000000000..57e691bb34 --- /dev/null +++ b/Tests/RunCMake/find_package-CPS/SymbolicComponents.cmake @@ -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) diff --git a/Tests/RunCMake/find_package-CPS/cps/symbolic.cps b/Tests/RunCMake/find_package-CPS/cps/symbolic.cps new file mode 100644 index 0000000000..e5c2e29f18 --- /dev/null +++ b/Tests/RunCMake/find_package-CPS/cps/symbolic.cps @@ -0,0 +1,17 @@ +{ + "components" : + { + "foo" : + { + "type" : "interface" + }, + "test" : + { + "type" : "symbolic" + } + }, + "cps_path" : "@prefix@", + "cps_version" : "0.13.0", + "name" : "Symbolic", + "version": "1.0" +} diff --git a/Tests/RunCMake/install/RunCMakeTest.cmake b/Tests/RunCMake/install/RunCMakeTest.cmake index 943db9a37c..9309f9a3ef 100644 --- a/Tests/RunCMake/install/RunCMakeTest.cmake +++ b/Tests/RunCMake/install/RunCMakeTest.cmake @@ -97,7 +97,7 @@ foreach(policy IN ITEMS NEW OLD WARN) run_install_test(CMP0177-${policy}) run_cmake_with_options(CMP0177-${policy}-verify -DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/CMP0177-${policy}-build/root-all - ) + ) endforeach() run_cmake(TARGETS-ImportedGlobal) run_cmake(TARGETS-NAMELINK_COMPONENT-bad-all) @@ -106,7 +106,7 @@ run_cmake(FILES-DESTINATION-TYPE) run_cmake(DIRECTORY-DESTINATION-TYPE) run_cmake(FILES-directory) if(NOT WIN32) - run_cmake(FILES-symlink-to-directory) + run_cmake(FILES-symlink-to-directory) endif() 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(DIRECTORY-OPTIONAL) run_install_test(TARGETS-Defaults) +run_install_test(TARGETS-SymbolicComponent) if(CMAKE_SYSTEM_NAME STREQUAL "Linux") run_install_test(TARGETS-NAMELINK-No-Tweak) diff --git a/Tests/RunCMake/install/TARGETS-SymbolicComponent-all-check.cmake b/Tests/RunCMake/install/TARGETS-SymbolicComponent-all-check.cmake new file mode 100644 index 0000000000..bf0cb0e54a --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-SymbolicComponent-all-check.cmake @@ -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() diff --git a/Tests/RunCMake/install/TARGETS-SymbolicComponent.cmake b/Tests/RunCMake/install/TARGETS-SymbolicComponent.cmake new file mode 100644 index 0000000000..8d551cf51b --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-SymbolicComponent.cmake @@ -0,0 +1,3 @@ +add_library(foo INTERFACE SYMBOLIC) +install(TARGETS foo EXPORT foo) +install(EXPORT foo DESTINATION . FILE foo.cmake)