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. 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) 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" + } + } +}