From 85721c4c56513e255fde7824c5520fde33f61ed3 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Wed, 12 Feb 2025 11:25:24 -0500 Subject: [PATCH 1/2] install(PACKAGE_INFO): Export required components Modify cmExportPackageInfoGenerator to record not just what packages are required, but what targets (components) are used by those requirements, and to populate the requirements' component lists accordingly. --- Source/cmExportPackageInfoGenerator.cxx | 34 ++++++++++++------- Source/cmExportPackageInfoGenerator.h | 2 +- .../PackageInfo/Requirements-check.cmake | 6 ++-- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/Source/cmExportPackageInfoGenerator.cxx b/Source/cmExportPackageInfoGenerator.cxx index 211347e7b7..8616e10737 100644 --- a/Source/cmExportPackageInfoGenerator.cxx +++ b/Source/cmExportPackageInfoGenerator.cxx @@ -127,9 +127,22 @@ void cmExportPackageInfoGenerator::GeneratePackageRequires( { if (!this->Requirements.empty()) { Json::Value& requirements = package["requires"]; + + // Build description for each requirement. for (auto const& requirement : this->Requirements) { + auto data = Json::Value{ Json::objectValue }; + + // Add required components. + if (!requirement.second.empty()) { + auto components = Json::Value{ Json::arrayValue }; + for (std::string const& component : requirement.second) { + components.append(component); + } + data["components"] = components; + } + // TODO: version, hint - requirements[requirement] = Json::Value{}; + requirements[requirement.first] = data; } } } @@ -257,10 +270,10 @@ bool cmExportPackageInfoGenerator::NoteLinkedTarget( return false; } + std::string component = linkedName.substr(prefix.length()); + this->LinkTargets.emplace(linkedName, cmStrCat(pkgName, ':', component)); // TODO: Record package version, hint. - this->Requirements.emplace(pkgName); - this->LinkTargets.emplace( - linkedName, cmStrCat(pkgName, ':', linkedName.substr(prefix.length()))); + this->Requirements[pkgName].emplace(std::move(component)); return true; } @@ -278,16 +291,13 @@ bool cmExportPackageInfoGenerator::NoteLinkedTarget( return false; } - auto pkgName = - cm::string_view{ linkNamespace.data(), linkNamespace.size() - 2 }; - + std::string pkgName{ linkNamespace.data(), linkNamespace.size() - 2 }; + std::string component = linkedTarget->GetExportName(); if (pkgName == this->GetPackageName()) { - this->LinkTargets.emplace(linkedName, - cmStrCat(':', linkedTarget->GetExportName())); + this->LinkTargets.emplace(linkedName, cmStrCat(':', component)); } else { - this->Requirements.emplace(pkgName); - this->LinkTargets.emplace( - linkedName, cmStrCat(pkgName, ':', linkedTarget->GetExportName())); + this->LinkTargets.emplace(linkedName, cmStrCat(pkgName, ':', component)); + this->Requirements[pkgName].emplace(std::move(component)); } return true; } diff --git a/Source/cmExportPackageInfoGenerator.h b/Source/cmExportPackageInfoGenerator.h index 6fe1e359d3..5014252b5f 100644 --- a/Source/cmExportPackageInfoGenerator.h +++ b/Source/cmExportPackageInfoGenerator.h @@ -110,5 +110,5 @@ private: std::vector DefaultConfigurations; std::map LinkTargets; - std::set Requirements; + std::map> Requirements; }; diff --git a/Tests/RunCMake/PackageInfo/Requirements-check.cmake b/Tests/RunCMake/PackageInfo/Requirements-check.cmake index 59a212f648..a0823553b3 100644 --- a/Tests/RunCMake/PackageInfo/Requirements-check.cmake +++ b/Tests/RunCMake/PackageInfo/Requirements-check.cmake @@ -8,8 +8,10 @@ expect_value("${content}" "interface" "components" "libb" "type") file(READ "${out_dir}/bar.cps" content) expect_value("${content}" "bar" "name") -expect_null("${content}" "requires" "foo") -expect_null("${content}" "requires" "test") +expect_array("${content}" 1 "requires" "foo" "components") +expect_value("${content}" "libb" "requires" "foo" "components" 0) +expect_array("${content}" 1 "requires" "test" "components") +expect_value("${content}" "liba" "requires" "test" "components" 0) expect_value("${content}" "interface" "components" "libc" "type") expect_value("${content}" "interface" "components" "libd" "type") From 647633e961565b46dbe8e88209db00849f861b4f Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Fri, 14 Feb 2025 11:50:29 -0500 Subject: [PATCH 2/2] Tests: Add CPS end-to-end test Add a test that validates that we can export a package in CPS format and import it again. This is fairly simplistic at the moment, but still serves to validate some recent fixes that are not covered by more targeted unit tests. --- Tests/RunCMake/CMakeLists.txt | 1 + Tests/RunCMake/CpsExportImport/CMakeLists.txt | 3 +++ .../CpsExportImport/RunCMakeTest.cmake | 24 +++++++++++++++++++ .../CpsExportImport/TestExecutable.cmake | 12 ++++++++++ .../CpsExportImport/TestLibrary.cmake | 14 +++++++++++ Tests/RunCMake/CpsExportImport/app.c | 13 ++++++++++ Tests/RunCMake/CpsExportImport/liba.c | 7 ++++++ Tests/RunCMake/CpsExportImport/libb.c | 13 ++++++++++ 8 files changed, 87 insertions(+) create mode 100644 Tests/RunCMake/CpsExportImport/CMakeLists.txt create mode 100644 Tests/RunCMake/CpsExportImport/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/CpsExportImport/TestExecutable.cmake create mode 100644 Tests/RunCMake/CpsExportImport/TestLibrary.cmake create mode 100644 Tests/RunCMake/CpsExportImport/app.c create mode 100644 Tests/RunCMake/CpsExportImport/liba.c create mode 100644 Tests/RunCMake/CpsExportImport/libb.c diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index e664ca333a..b6304a89fe 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -396,6 +396,7 @@ set_property(TEST RunCMake.CompilerId APPEND PROPERTY LABELS "CUDA" "HIP" "ISPC" add_RunCMake_test(CompilerTest ${CMake_TEST_LANG_VARS}) set_property(TEST RunCMake.CompilerTest APPEND PROPERTY LABELS "CUDA" "HIP" "ISPC" "Fortran") add_RunCMake_test(Configure -DMSVC_IDE=${MSVC_IDE}) +add_RunCMake_test(CpsExportImport) add_RunCMake_test(DisallowedCommands) if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles|Ninja") add_RunCMake_test(ExportCompileCommands) diff --git a/Tests/RunCMake/CpsExportImport/CMakeLists.txt b/Tests/RunCMake/CpsExportImport/CMakeLists.txt new file mode 100644 index 0000000000..955802cde9 --- /dev/null +++ b/Tests/RunCMake/CpsExportImport/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 4.0) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/CpsExportImport/RunCMakeTest.cmake b/Tests/RunCMake/CpsExportImport/RunCMakeTest.cmake new file mode 100644 index 0000000000..dff26eb741 --- /dev/null +++ b/Tests/RunCMake/CpsExportImport/RunCMakeTest.cmake @@ -0,0 +1,24 @@ +include(RunCMake) + +set(RunCMake_TEST_OPTIONS + -Wno-dev + "-DCMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO:STRING=b80be207-778e-46ba-8080-b23bba22639e" + "-DCMAKE_EXPERIMENTAL_FIND_CPS_PACKAGES:STRING=e82e467b-f997-4464-8ace-b00808fff261" + ) + +function(build_project test) + set(RunCMake_TEST_NO_CLEAN FALSE) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build) + if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG) + list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release) + endif() + + run_cmake(${test}) + + set(RunCMake_TEST_NO_CLEAN TRUE) + run_cmake_command(${test}-build ${CMAKE_COMMAND} --build . --config Release) + run_cmake_command(${test}-install ${CMAKE_COMMAND} --install . --config Release) +endfunction() + +build_project(TestLibrary) +build_project(TestExecutable) diff --git a/Tests/RunCMake/CpsExportImport/TestExecutable.cmake b/Tests/RunCMake/CpsExportImport/TestExecutable.cmake new file mode 100644 index 0000000000..cced129ec3 --- /dev/null +++ b/Tests/RunCMake/CpsExportImport/TestExecutable.cmake @@ -0,0 +1,12 @@ +project(TestLibrary C) + +set(CMAKE_PREFIX_PATH "${CMAKE_BINARY_DIR}/../install") +set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/../install") + +find_package(libb REQUIRED COMPONENTS libb) + +add_executable(app app.c) + +target_link_libraries(app PUBLIC libb::libb) + +install(TARGETS app DESTINATION bin) diff --git a/Tests/RunCMake/CpsExportImport/TestLibrary.cmake b/Tests/RunCMake/CpsExportImport/TestLibrary.cmake new file mode 100644 index 0000000000..a984f2bd27 --- /dev/null +++ b/Tests/RunCMake/CpsExportImport/TestLibrary.cmake @@ -0,0 +1,14 @@ +project(TestLibrary C) + +set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/../install") + +add_library(liba SHARED liba.c) +add_library(libb SHARED libb.c) + +target_link_libraries(libb PUBLIC liba) + +install(TARGETS liba EXPORT liba DESTINATION lib) +install(PACKAGE_INFO liba DESTINATION cps EXPORT liba) + +install(TARGETS libb EXPORT libb DESTINATION lib) +install(PACKAGE_INFO libb DESTINATION cps EXPORT libb) diff --git a/Tests/RunCMake/CpsExportImport/app.c b/Tests/RunCMake/CpsExportImport/app.c new file mode 100644 index 0000000000..9ad782984b --- /dev/null +++ b/Tests/RunCMake/CpsExportImport/app.c @@ -0,0 +1,13 @@ +#include + +extern +#ifdef _WIN32 +__declspec(dllimport) +#endif +int ask(void); + +int main(void) +{ + printf("%i\n", ask()); + return 0; +} diff --git a/Tests/RunCMake/CpsExportImport/liba.c b/Tests/RunCMake/CpsExportImport/liba.c new file mode 100644 index 0000000000..a2e2267f8a --- /dev/null +++ b/Tests/RunCMake/CpsExportImport/liba.c @@ -0,0 +1,7 @@ +#ifdef _WIN32 +__declspec(dllexport) +#endif +int answer(void) +{ + return 42; +} diff --git a/Tests/RunCMake/CpsExportImport/libb.c b/Tests/RunCMake/CpsExportImport/libb.c new file mode 100644 index 0000000000..8ba04af128 --- /dev/null +++ b/Tests/RunCMake/CpsExportImport/libb.c @@ -0,0 +1,13 @@ +extern +#ifdef _WIN32 +__declspec(dllimport) +#endif +int answer(void); + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int ask(void) +{ + return answer(); +}