From 9fb5f0fb5b3ffac72a143cd953216e8689349966 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Thu, 9 Jul 2026 14:50:30 -0400 Subject: [PATCH 1/3] CPS: Implement importing of file sets Add (partial) file set import to CPS. For now, only headers ("includes") are supported; see comments in commit a5b38fb898 (CPS: Implement exporting of file sets, 2026-06-29). This is the companion to those changes. --- Source/cmPackageInfoReader.cxx | 64 ++++++++++++++- Source/cmPackageInfoReader.h | 3 + Tests/FindPackageCpsTest/CMakeLists.txt | 78 ++++++++++++++++++- .../cps/filesets-anonymous.cps | 23 ++++++ .../FindPackageCpsTest/cps/filesets-named.cps | 49 ++++++++++++ 5 files changed, 214 insertions(+), 3 deletions(-) create mode 100644 Tests/FindPackageCpsTest/cps/filesets-anonymous.cps create mode 100644 Tests/FindPackageCpsTest/cps/filesets-named.cps diff --git a/Source/cmPackageInfoReader.cxx b/Source/cmPackageInfoReader.cxx index 2fa5deed49..27ae441aca 100644 --- a/Source/cmPackageInfoReader.cxx +++ b/Source/cmPackageInfoReader.cxx @@ -20,6 +20,8 @@ #include "cmCxxModuleMetadata.h" #include "cmExecutionStatus.h" +#include "cmFileSet.h" +#include "cmFileSetMetadata.h" #include "cmList.h" #include "cmListFileCache.h" #include "cmMakefile.h" @@ -131,7 +133,7 @@ bool CheckSchemaVersion(Json::Value const& data) // Check that we understand this version. return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, version, "0.13") && - cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, version, "0.15"); + cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, version, "0.16"); // TODO Eventually this probably needs to return the version tuple, and // should share code with cmPackageInfoReader::ParseVersion. @@ -228,6 +230,20 @@ std::vector ReadList(Json::Value const& data, char const* key) return ReadList(data[key]); } +Json::Value GetExtensions(Json::Value const& data) +{ + if (data.isObject()) { + Json::Value const& extensions = data["extensions"]; + if (extensions.isObject()) { + Json::Value const& cmake = extensions["cmake"]; + if (cmake.isObject()) { + return cmake; + } + } + } + return Json::Value{ Json::objectValue }; +} + std::string NormalizeTargetName(std::string const& name, std::string const& context) { @@ -869,9 +885,55 @@ cmTarget* cmPackageInfoReader::AddLibraryComponent( this->SetTargetProperties(makefile, target, *ci, package, IterKey(ci)); } + // Add target sources. + this->AddTargetSources(makefile, target, data["file_sets"]); + return target; } +void cmPackageInfoReader::AddTargetSources(cmMakefile* makefile, + cmTarget* target, + Json::Value const& data) const +{ + if (data.isArray()) { + for (Json::Value const& fs : data) { + if (fs.isObject()) { + std::string const& type = ToString(fs["type"]); + std::string const& root = this->ResolvePath(ToString(fs["root"])); + std::vector files = ReadList(fs["files"]); + + if (files.empty() || root.empty() || type != "includes") { + continue; + } + + Json::Value const& ext = GetExtensions(fs); + std::string const& name = [&] { + std::string const& extName = ToString(ext["name@v1"]); + if (!extName.empty()) { + return extName; + } + return std::string{ cm::FileSetMetadata::HEADERS }; + }(); + + // TODO: When we support more than one file set type, check that we + // don't see the same 'name' on sets of different types. + auto fileSet = target->GetOrCreateFileSet( + name, std::string{ cm::FileSetMetadata::HEADERS }, + cm::FileSetMetadata::Visibility::Interface); + cmListFileBacktrace const& bt = makefile->GetBacktrace(); + + for (std::string& file : files) { + file = cmStrCat(root, '/', file); + } + fileSet.first->AddFileEntry( + BT{ cmList{ files }.to_string(), bt }); + + fileSet.first->AddDirectoryEntry(BT{ root, bt }); + } + } + } +} + bool cmPackageInfoReader::ImportTargets(cmMakefile* makefile, cmExecutionStatus& status, cm::ImportedTargetScope scope) diff --git a/Source/cmPackageInfoReader.h b/Source/cmPackageInfoReader.h index 2454f14211..0228d4d984 100644 --- a/Source/cmPackageInfoReader.h +++ b/Source/cmPackageInfoReader.h @@ -99,6 +99,9 @@ private: void AddTargetConfiguration(cmTarget* target, cm::string_view configuration) const; + void AddTargetSources(cmMakefile* makefile, cmTarget* target, + Json::Value const& data) const; + void SetTargetProperties(cmMakefile* makefile, cmTarget* target, Json::Value const& data, std::string const& package, cm::string_view configuration) const; diff --git a/Tests/FindPackageCpsTest/CMakeLists.txt b/Tests/FindPackageCpsTest/CMakeLists.txt index 3d6f01a729..4829621304 100644 --- a/Tests/FindPackageCpsTest/CMakeLists.txt +++ b/Tests/FindPackageCpsTest/CMakeLists.txt @@ -27,9 +27,9 @@ function(expect PACKAGE VAR OP VALUE WHAT) endif() endfunction() -function(expect_property TARGET PROPERTY DESCRIPTION EXPECTED) +function(expect_property TARGET PROPERTY DESCRIPTION) get_target_property(actual ${TARGET} ${PROPERTY}) - if(NOT "${actual}" STREQUAL "${EXPECTED}") + if(NOT "${actual}" STREQUAL "${ARGN}") message(SEND_ERROR "${TARGET} has wrong ${DESCRIPTION} '${actual}' !") endif() endfunction() @@ -375,3 +375,77 @@ else() DefaultConfigurationsTest::Target2 IMPORTED_CONFIGURATIONS "configurations" "TEST") endif() + +############################################################################### +# Test unnamed file sets. + +find_package(FileSets-Anonymous) +if(NOT FileSets-Anonymous_FOUND) + message(SEND_ERROR "FileSets-Anonymous not found !") +elseif(NOT TARGET FileSets-Anonymous::Target) + message(SEND_ERROR "FileSets-Anonymous::Target missing !") +else() + expect_property( + FileSets-Anonymous::Target INTERFACE_HEADER_SETS + "include set names" "HEADERS") + expect_property( + FileSets-Anonymous::Target HEADER_DIRS + "include set roots" + "${CMAKE_SOURCE_DIR}/include" + "${CMAKE_SOURCE_DIR}/include") + expect_property( + FileSets-Anonymous::Target HEADER_DIRS_HEADERS + "include set 'HEADERS' roots" + "${CMAKE_SOURCE_DIR}/include" + "${CMAKE_SOURCE_DIR}/include") + expect_property( + FileSets-Anonymous::Target HEADER_SET + "include set files" + "${CMAKE_SOURCE_DIR}/include/header1.h" + "${CMAKE_SOURCE_DIR}/include/header2.h" + "${CMAKE_SOURCE_DIR}/include/header3.h") + expect_property( + FileSets-Anonymous::Target HEADER_SET_HEADERS + "include set 'HEADERS' files" + "${CMAKE_SOURCE_DIR}/include/header1.h" + "${CMAKE_SOURCE_DIR}/include/header2.h" + "${CMAKE_SOURCE_DIR}/include/header3.h") +endif() + +############################################################################### +# Test named file sets. + +find_package(FileSets-Named) +if(NOT FileSets-Named_FOUND) + message(SEND_ERROR "FileSets-Named not found !") +elseif(NOT TARGET FileSets-Named::Target) + message(SEND_ERROR "FileSets-Named::Target missing !") +else() + expect_property( + FileSets-Named::Target INTERFACE_HEADER_SETS + "include set names" "foo;bar") + expect_property( + FileSets-Named::Target HEADER_DIRS_foo + "include set roots" + "${CMAKE_SOURCE_DIR}/include/a" + "${CMAKE_SOURCE_DIR}/include/b") + expect_property( + FileSets-Named::Target HEADER_DIRS_foo + "include set 'foo' roots" + "${CMAKE_SOURCE_DIR}/include/a" + "${CMAKE_SOURCE_DIR}/include/b") + expect_property( + FileSets-Named::Target HEADER_DIRS_bar + "include set 'bar' roots" + "${CMAKE_SOURCE_DIR}/include") + expect_property( + FileSets-Named::Target HEADER_SET_foo + "include set 'foo' files" + "${CMAKE_SOURCE_DIR}/include/a/foo1.h" + "${CMAKE_SOURCE_DIR}/include/a/foo2.h" + "${CMAKE_SOURCE_DIR}/include/b/foo3.h") + expect_property( + FileSets-Named::Target HEADER_SET_bar + "include set 'bar' files" + "${CMAKE_SOURCE_DIR}/include/bar.h") +endif() diff --git a/Tests/FindPackageCpsTest/cps/filesets-anonymous.cps b/Tests/FindPackageCpsTest/cps/filesets-anonymous.cps new file mode 100644 index 0000000000..898463a7fb --- /dev/null +++ b/Tests/FindPackageCpsTest/cps/filesets-anonymous.cps @@ -0,0 +1,23 @@ +{ + "cps_version": "0.15.0", + "name": "FileSets-Anonymous", + "cps_path": "@prefix@/cps", + "components": { + "Target": { + "file_sets": + [ + { + "type": "includes", + "root": "@prefix@/include", + "files": [ "header1.h", "header2.h" ] + }, + { + "type": "includes", + "root": "@prefix@/include", + "files": [ "header3.h" ] + } + ], + "type": "interface" + } + } +} diff --git a/Tests/FindPackageCpsTest/cps/filesets-named.cps b/Tests/FindPackageCpsTest/cps/filesets-named.cps new file mode 100644 index 0000000000..3e8911a4af --- /dev/null +++ b/Tests/FindPackageCpsTest/cps/filesets-named.cps @@ -0,0 +1,49 @@ +{ + "cps_version": "0.15.0", + "name": "FileSets-Named", + "cps_path": "@prefix@/cps", + "components": { + "Target": { + "file_sets": + [ + { + "extensions": + { + "cmake": + { + "name@v1": "foo" + } + }, + "type": "includes", + "root": "@prefix@/include/a", + "files": [ "foo1.h", "foo2.h" ] + }, + { + "extensions": + { + "cmake": + { + "name@v1": "foo" + } + }, + "type": "includes", + "root": "@prefix@/include/b", + "files": [ "foo3.h" ] + }, + { + "extensions": + { + "cmake": + { + "name@v1": "bar" + } + }, + "type": "includes", + "root": "@prefix@/include", + "files": [ "bar.h" ] + } + ], + "type": "interface" + } + } +} From 232f9473c748ae8d28a4d2925aaa9cadde65e982 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Thu, 9 Jul 2026 11:10:31 -0400 Subject: [PATCH 2/3] CPS: Fix export version Commit a5b38fb898 (CPS: Implement exporting of file sets, 2026-06-29) added support for exporting file sets, but neglected to bump the CPS version to the schema version that added file sets. While it happens that this is somewhat fortuitous, since prior to the previous commit, this would have resulted in writing CPS files that we couldn't read, it still needs to be fixed. --- Source/cmExportPackageInfoGenerator.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/cmExportPackageInfoGenerator.cxx b/Source/cmExportPackageInfoGenerator.cxx index 2552a14113..e994eb7a77 100644 --- a/Source/cmExportPackageInfoGenerator.cxx +++ b/Source/cmExportPackageInfoGenerator.cxx @@ -34,7 +34,7 @@ #include "cmTarget.h" #include "cmTargetTypes.h" -static std::string const kCPS_VERSION_STR = "0.14.1"; +static std::string const kCPS_VERSION_STR = "0.15.0"; cmExportPackageInfoGenerator::cmExportPackageInfoGenerator( cmPackageInfoArguments arguments) From cc94d43f529079703183d234351f57b024109625 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Thu, 9 Jul 2026 16:08:47 -0400 Subject: [PATCH 3/3] CPS: Add release note for file set import/export --- Help/release/dev/cps-file-sets.rst | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Help/release/dev/cps-file-sets.rst diff --git a/Help/release/dev/cps-file-sets.rst b/Help/release/dev/cps-file-sets.rst new file mode 100644 index 0000000000..285e0a36e3 --- /dev/null +++ b/Help/release/dev/cps-file-sets.rst @@ -0,0 +1,4 @@ +cps-file-sets +------------- + +* CPS import and export now supports header file sets.