diff --git a/Help/command/install.rst b/Help/command/install.rst index f3c4d2f603..68caf6818a 100644 --- a/Help/command/install.rst +++ b/Help/command/install.rst @@ -979,7 +979,7 @@ Signatures Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``. - Installs a |CPS|_ file exporting targets for dependent projects: + Installs a |CPS|_ ("CPS") file exporting targets for dependent projects: .. code-block:: cmake @@ -1105,6 +1105,20 @@ Signatures use of ``LOWER_CASE_FILE`` should be consistent between the main package and any appendices. + .. note:: + Because it is intended to be portable across multiple build tools, CPS + may not support all features that are allowed in CMake-script exports. In + particular, support for generator expressions in interface properties is + limited at this time to configuration-dependent expressions. + + .. note:: + This is the recommended way to generate |CPS| package information for a + project. For distributors whose users may require CPS package information + when making changes to the project's build files is not practical, the + :variable:`CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO` variable may be used to + generate ``.cps`` files from :command:`install(EXPORT)` calls. Refer to + the variable's documentation for usage and caveats. + .. signature:: install(RUNTIME_DEPENDENCY_SET [...]) diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 6c127161e3..e958dbdda5 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -263,6 +263,7 @@ Variables that Change Behavior /variable/CMAKE_INCLUDE_PATH /variable/CMAKE_INSTALL_DEFAULT_COMPONENT_NAME /variable/CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS + /variable/CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO /variable/CMAKE_INSTALL_MESSAGE /variable/CMAKE_INSTALL_PREFIX /variable/CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT diff --git a/Help/variable/CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO.rst b/Help/variable/CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO.rst new file mode 100644 index 0000000000..f5b7b27241 --- /dev/null +++ b/Help/variable/CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO.rst @@ -0,0 +1,122 @@ +CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO +------------------------------------- + +.. versionadded:: 4.3 + +.. note:: + + This variable is meaningful only when experimental support has been enabled + by the ``CMAKE_EXPERIMENTAL_FIXME`` gate. + +A list of directives instructing CMake to install |CPS| package information +when exported target information is installed via :command:`install(EXPORT)`. +The value is treated as a list, with each directive having the form +``:[/[l][a][/]]``. +Slashes are used to separate different components of the directive. + +Note that this feature is intended for package distributors, and should +**only** be used when editing a project's CMake script is not feasible. +Developers should use :command:`install(PACKAGE_INFO)` directly. + +Additionally, because ``CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO`` functions by +emulating a call to :command:`install(PACKAGE_INFO)`, using it with a project +that is already calling :command:`install(PACKAGE_INFO)` directly may result +in conflicting installation directives, which will usually cause the project's +configure step to fail. + +The meaning of the values is as follows: + +```` + Name of the export for which package information should be installed. + +```` + Name of the package for which to generate package information. This is also + the name that users would use in a :command:`find_package` call. + +``l`` + Optional. Specifies that the name of the package information file on disk + should be lower case. See the ``LOWER_CASE_FILE`` option of + :command:`install(PACKAGE_INFO)`. + +``a`` + Optional. Specifies that an appendix ```` should be created + rather than a root package description. See the ``APPENDIX`` option of + :command:`install(PACKAGE_INFO)`. Note that additional information + (see below) cannot be added to appendices. + +```` + Optional. Specifies the destination to which the package information file + should be installed. See the ``DESTINATION`` option of + :command:`install(PACKAGE_INFO)`. Note that the default is a + platform-specific location that is appropriate for |CPS| files in most + instances, *not* the ``DESTINATION`` of the :command:`install(EXPORT)` + which the directive matched. + +For non-appendices, CMake will also infer additional information from several +CMake variables of the form ``_EXPORT_PACKAGE_INFO_``. The +values of these are first processed as if by :command:`string(CONFIGURE)` with +the ``@ONLY`` option. These are optional, and their effect is equivalent to +passing their value to the ```` option of the +:command:`install(PACKAGE_INFO)` command. + +The additional variables are: + + * ``_EXPORT_PACKAGE_INFO_VERSION`` + * ``_EXPORT_PACKAGE_INFO_COMPAT_VERSION`` + * ``_EXPORT_PACKAGE_INFO_VERSION_SCHEMA`` + * ``_EXPORT_PACKAGE_INFO_LICENSE`` + * ``_EXPORT_PACKAGE_INFO_DEFAULT_LICENSE`` + * ``_EXPORT_PACKAGE_INFO_DEFAULT_CONFIGURATIONS`` + +Ideally, the version should be set to ``@PROJECT_VERSION@``. However, +some projects may not use the ``VERSION`` option of the :command:`project` +command. + +Example +^^^^^^^ + +Consider the following (simplified) project: + +.. code-block:: cmake + + project(Example VERSION 1.2.3 SPDX_LICENSE "BSD-3-Clause") + + add_library(foo ...) + add_library(bar ...) + + install(TARGETS foo EXPORT required-targets) + install(TARGETS bar EXPORT optional-targets) + + install(EXPORT required-targets FILE example-targets.cmake ...) + install(EXPORT optional-targets FILE example-optional-targets.cmake ...) + +In this example, let ``example-targets.cmake`` be a file which is always +installed, and ``example-optional-targets.cmake`` be a file which is +optionally installed (e.g. is distributed as part of a separate package which +depends on the 'base' package). + +Now, imagine we are a distributor that wants to make |CPS| package information +files available to our users, but we do not want to modify the project's build +files. We can do this by passing the following arguments to CMake: + +.. code-block:: + + -DCMAKE_EXPERIMENTAL_FIXME= + -DCMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO=\ + required-targets:Example/l;\ + optional-targets:Example/laoptional + -Drequired-targets_EXPORT_PACKAGE_INFO_VERSION=@Example_VERSION@ + -Drequired-targets_EXPORT_PACKAGE_INFO_LICENSE=@Example_SPDX_LICENSE@ + +(Whitespace and line continuation characters, added for readability, should +be removed in real usage. Arguments may need to be quoted to prevent being +reinterpreted by the command shell.) + +This will cause CMake to also create and install the files ``example.cps`` and +``example-optional.cps`` which describe the ``Example`` package. We could +also specify the version and license information using substitutions provided +by the package build system (e.g. rpm, dpkg) if the project does not provide +this information via the :command:`project` command. + +.. _CPS: https://cps-org.github.io/cps/ +.. |CPS| replace:: Common Package Specification diff --git a/Source/cmExperimental.cxx b/Source/cmExperimental.cxx index b7aec465d4..fe180b611a 100644 --- a/Source/cmExperimental.cxx +++ b/Source/cmExperimental.cxx @@ -55,6 +55,15 @@ cmExperimental::FeatureData const LookupTable[] = { "experimentation and feedback to CMake developers.", {}, cmExperimental::TryCompileCondition::Always }, + // MappedPackageInfo + { "MappedPackageInfo", + "ababa1b5-7099-495f-a9cd-e22d38f274f2", + "CMAKE_EXPERIMENTAL_MAPPED_PACKAGE_INFO", + "CMake's support for generating package information in the Common Package " + "Specification format from CMake script exports is experimental. It is " + "meant only for experimentation and feedback to CMake developers.", + {}, + cmExperimental::TryCompileCondition::Always }, // ExportBuildDatabase { "ExportBuildDatabase", "73194a1d-c0b5-41b9-9190-a4512925e192", diff --git a/Source/cmExperimental.h b/Source/cmExperimental.h index 54fd691e85..5171e189c6 100644 --- a/Source/cmExperimental.h +++ b/Source/cmExperimental.h @@ -21,6 +21,7 @@ public: CxxImportStd, ImportPackageInfo, ExportPackageInfo, + MappedPackageInfo, ExportBuildDatabase, Instrumentation, diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index e66fa8a767..15267d04a6 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -2035,6 +2035,152 @@ bool HandleExportAndroidMKMode(std::vector const& args, #endif } +#ifndef CMAKE_BOOTSTRAP +cm::optional MatchExport(cm::string_view directive, + std::string const& exportName) +{ + std::string::size_type const l = exportName.size(); + if (directive.substr(0, l) == exportName) { + if (directive.size() > l && directive[l] == ':') { + return directive.substr(l + 1); + } + } + return cm::nullopt; +} + +void AssignValue(std::string& dest, std::string const& value) +{ + dest = value; +} + +void AssignValue(std::vector& dest, std::string const& value) +{ + dest = cmList{ value }.data(); +} + +template +void GetExportArgumentFromVariable(cmMakefile const* makefile, + cmExportSet const& exportSet, + cm::string_view suffix, T& variable) +{ + std::string const& name = + cmStrCat(exportSet.GetName(), "_EXPORT_PACKAGE_INFO_"_s, suffix); + if (cmValue const& value = makefile->GetDefinition(name)) { + std::string realValue; + makefile->ConfigureString(value, realValue, true, false); + AssignValue(variable, realValue); + } +} + +bool HandleMappedPackageInfo( + cmExportSet& exportSet, cm::string_view directive, Helper& helper, + cmInstallCommandArguments const& installCommandArgs, + cmExecutionStatus& status, cmInstallGenerator::MessageLevel message, + std::string const& cxxModulesDirectory) +{ + cmPackageInfoArguments arguments; + + // Extract information from the directive. + std::string::size_type const n = directive.find('/'); + if (n != std::string::npos) { + arguments.PackageName = std::string{ directive.substr(0, n) }; + directive = directive.substr(n + 1); + + if (!directive.empty() && directive[0] == 'l') { + arguments.LowerCase = true; + directive = directive.substr(1); + } + + if (!directive.empty() && directive[0] == 'a') { + std::string::size_type const d = directive.find('/'); + if (d != std::string::npos) { + arguments.Appendix = std::string{ directive.substr(1, d - 1) }; + directive = directive.substr(d); + } else { + arguments.Appendix = std::string{ directive.substr(1) }; + directive = {}; + } + + if (arguments.Appendix.empty()) { + status.SetError(cmStrCat( + "CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO given APPENDIX " + R"(directive for export ")"_s, + exportSet.GetName(), R"(", but no appendix name was provided.)"_s)); + return false; + } + } + + if (!directive.empty()) { + if (directive[0] != '/') { + status.SetError( + cmStrCat("CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO given unrecognized " + R"(directive ")"_s, + directive, R"(".)"_s)); + return false; + } + + directive = directive.substr(1); + } + } else { + arguments.PackageName = std::string{ directive }; + directive = {}; + } + + if (arguments.PackageName.empty()) { + status.SetError( + cmStrCat("CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO missing package name " + R"(for export ")"_s, + exportSet.GetName(), R"(".)"_s)); + return false; + } + + // Build destination. + std::string dest = std::string{ directive }; + if (dest.empty()) { + if (helper.Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Windows") { + dest = std::string{ "cps"_s }; + } else { + dest = cmStrCat(helper.GetLibraryDestination(nullptr), "/cps/", + arguments.GetPackageDirName()); + } + } + + if (arguments.Appendix.empty()) { + // Get additional export information from variables. + GetExportArgumentFromVariable( // BR + helper.Makefile, exportSet, "VERSION"_s, arguments.Version); + GetExportArgumentFromVariable( // BR + helper.Makefile, exportSet, "COMPAT_VERSION"_s, arguments.VersionCompat); + GetExportArgumentFromVariable( // BR + helper.Makefile, exportSet, "VERSION_SCHEMA"_s, arguments.VersionSchema); + GetExportArgumentFromVariable( // BR + helper.Makefile, exportSet, "LICENSE"_s, arguments.License); + GetExportArgumentFromVariable( // BR + helper.Makefile, exportSet, "DEFAULT_LICENSE"_s, + arguments.DefaultLicense); + GetExportArgumentFromVariable( // BR + helper.Makefile, exportSet, "DEFAULT_CONFIGURATIONS"_s, + arguments.DefaultConfigs); + } + + // Sanity-check export information. + if (!arguments.Check(status)) { + return false; + } + + // Create the package info generator. + helper.Makefile->AddInstallGenerator( + cm::make_unique( + &exportSet, dest, installCommandArgs.GetPermissions(), + installCommandArgs.GetConfigurations(), + installCommandArgs.GetComponent(), message, + installCommandArgs.GetExcludeFromAll(), std::move(arguments), + cxxModulesDirectory, helper.Makefile->GetBacktrace())); + + return true; +} +#endif + bool HandleExportMode(std::vector const& args, cmExecutionStatus& status) { @@ -2135,6 +2281,28 @@ bool HandleExportMode(std::vector const& args, helper.Makefile->GetGlobalGenerator()->AddInstallComponent( ica.GetComponent()); +#ifndef CMAKE_BOOTSTRAP + // Check if PACKAGE_INFO export has been requested for this export set. + if (cmExperimental::HasSupportEnabled( + status.GetMakefile(), cmExperimental::Feature::ExportPackageInfo) && + cmExperimental::HasSupportEnabled( + status.GetMakefile(), cmExperimental::Feature::MappedPackageInfo)) { + if (cmValue const& piExports = helper.Makefile->GetDefinition( + "CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO")) { + for (auto const& pie : cmList{ piExports }) { + cm::optional const directive = MatchExport(pie, exp); + if (directive) { + if (!HandleMappedPackageInfo(exportSet, *directive, helper, ica, + status, message, + cxx_modules_directory)) { + return false; + } + } + } + } + } +#endif + // Create the export install generator. helper.Makefile->AddInstallGenerator( cm::make_unique( diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 880776be0d..3c67c3a7b3 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -1335,6 +1335,7 @@ add_RunCMake_test(AutoExportDll add_RunCMake_test(AndroidMK) add_RunCMake_test(ExportPackageInfo) add_RunCMake_test(InstallPackageInfo) +add_RunCMake_test(InstallExportsAsPackageInfo) if(CMake_TEST_ANDROID_NDK OR CMake_TEST_ANDROID_STANDALONE_TOOLCHAIN) if(NOT "${CMAKE_GENERATOR}" MATCHES "Make|Ninja|Visual Studio 1[456]") diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/Assertions.cmake b/Tests/RunCMake/InstallExportsAsPackageInfo/Assertions.cmake new file mode 100644 index 0000000000..068074da2a --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/Assertions.cmake @@ -0,0 +1,39 @@ +macro(_expect entity op actual expected) + if(NOT "${actual}" ${op} "${expected}") + list(JOIN ARGN "." name) + set(RunCMake_TEST_FAILED + "Attribute '${name}' ${entity} '${actual}' does not match expected ${entity} '${expected}'" PARENT_SCOPE) + return() + endif() +endmacro() + +function(expect_value content expected_value) + string(JSON actual_value GET "${content}" ${ARGN}) + _expect("value" STREQUAL "${actual_value}" "${expected_value}" ${ARGN}) +endfunction() + +function(expect_array content expected_length) + string(JSON actual_type TYPE "${content}" ${ARGN}) + _expect("type" STREQUAL "${actual_type}" "ARRAY" ${ARGN}) + + string(JSON actual_length LENGTH "${content}" ${ARGN}) + _expect("length" EQUAL "${actual_length}" "${expected_length}" ${ARGN}) +endfunction() + +function(expect_object content) + string(JSON actual_type TYPE "${content}" ${ARGN}) + _expect("type" STREQUAL "${actual_type}" "OBJECT" ${ARGN}) +endfunction() + +function(expect_null content) + string(JSON actual_type TYPE "${content}" ${ARGN}) + _expect("type" STREQUAL "${actual_type}" "NULL" ${ARGN}) +endfunction() + +function(expect_missing content) + string(JSON value ERROR_VARIABLE error GET "${content}" ${ARGN}) + if(NOT value MATCHES "^(.*-)?NOTFOUND$") + set(RunCMake_TEST_FAILED + "Attribute '${ARGN}' is unexpectedly present" PARENT_SCOPE) + endif() +endfunction() diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/BadDirective-result.txt b/Tests/RunCMake/InstallExportsAsPackageInfo/BadDirective-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/BadDirective-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/BadDirective-stderr.txt b/Tests/RunCMake/InstallExportsAsPackageInfo/BadDirective-stderr.txt new file mode 100644 index 0000000000..10cead84d8 --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/BadDirective-stderr.txt @@ -0,0 +1,5 @@ +CMake Error at BadDirective\.cmake:2 \(install\): + install CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO given unrecognized directive + "error"\. +Call Stack \(most recent call first\): + CMakeLists\.txt:3 \(include\) diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/BadDirective.cmake b/Tests/RunCMake/InstallExportsAsPackageInfo/BadDirective.cmake new file mode 100644 index 0000000000..e967511d5e --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/BadDirective.cmake @@ -0,0 +1,2 @@ +set(CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO foo:foo/error) +install(EXPORT foo FILE foo-targets.cmake DESTINATION .) diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/CMakeLists.txt b/Tests/RunCMake/InstallExportsAsPackageInfo/CMakeLists.txt new file mode 100644 index 0000000000..abd58e2f9a --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 4.2) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/ExperimentalGate.cmake b/Tests/RunCMake/InstallExportsAsPackageInfo/ExperimentalGate.cmake new file mode 100644 index 0000000000..6675f623b7 --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/ExperimentalGate.cmake @@ -0,0 +1,6 @@ +unset(CMAKE_EXPERIMENTAL_MAPPED_PACKAGE_INFO) +set(CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO foo:) + +add_library(foo INTERFACE) +install(TARGETS foo EXPORT foo DESTINATION .) +install(EXPORT foo FILE foo-targets.cmake DESTINATION .) diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/ExperimentalWarning-stderr.txt b/Tests/RunCMake/InstallExportsAsPackageInfo/ExperimentalWarning-stderr.txt new file mode 100644 index 0000000000..b761f9c80e --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/ExperimentalWarning-stderr.txt @@ -0,0 +1,7 @@ +CMake Warning \(dev\) at ExperimentalWarning\.cmake:13 \(install\): + CMake's support for generating package information in the Common Package + Specification format from CMake script exports is experimental\. It is + meant only for experimentation and feedback to CMake developers\. +Call Stack \(most recent call first\): + CMakeLists\.txt:3 \(include\) +This warning is for project developers\. Use -Wno-dev to suppress it\. diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/ExperimentalWarning.cmake b/Tests/RunCMake/InstallExportsAsPackageInfo/ExperimentalWarning.cmake new file mode 100644 index 0000000000..22fcb465b3 --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/ExperimentalWarning.cmake @@ -0,0 +1,13 @@ +set( + CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO + "b80be207-778e-46ba-8080-b23bba22639e" + ) +set( + CMAKE_EXPERIMENTAL_MAPPED_PACKAGE_INFO + "ababa1b5-7099-495f-a9cd-e22d38f274f2" + ) +unset(CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO) + +add_library(foo INTERFACE) +install(TARGETS foo EXPORT foo DESTINATION .) +install(EXPORT foo FILE foo-targets.cmake DESTINATION .) diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/LowerCase-check.cmake b/Tests/RunCMake/InstallExportsAsPackageInfo/LowerCase-check.cmake new file mode 100644 index 0000000000..09a724620d --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/LowerCase-check.cmake @@ -0,0 +1,27 @@ +include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake) + +set(out_dir "${RunCMake_BINARY_DIR}/LowerCase-build/CMakeFiles/Export/510c5684a4a8a792eadfb55bc9744983") + +function(expect_in_list list value) + list(FIND ${list} "${value}" index) + if(${index} EQUAL -1) + set(RunCMake_TEST_FAILED + "Expected '${value}' in ${list} ('${${list}}'), but it was not found" PARENT_SCOPE) + endif() +endfunction() + +file(GLOB files + LIST_DIRECTORIES false + RELATIVE "${out_dir}" + "${out_dir}/*.cps" +) +expect_in_list(files "farm.cps") +expect_in_list(files "farm-extra.cps") + +file(READ "${out_dir}/farm.cps" content) +expect_value("${content}" "Farm" "name") +expect_value("${content}" "interface" "components" "Cow" "type") + +file(READ "${out_dir}/farm-extra.cps" content) +expect_value("${content}" "Farm" "name") +expect_value("${content}" "interface" "components" "Pig" "type") diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/LowerCase.cmake b/Tests/RunCMake/InstallExportsAsPackageInfo/LowerCase.cmake new file mode 100644 index 0000000000..f08f39fc4e --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/LowerCase.cmake @@ -0,0 +1,12 @@ +set(CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO + cow:Farm/l/cps + pig:Farm/laextra/cps +) + +add_library(Cow INTERFACE) +add_library(Pig INTERFACE) + +install(TARGETS Cow EXPORT cow) +install(TARGETS Pig EXPORT pig) +install(EXPORT cow FILE farm-targets.cmake DESTINATION .) +install(EXPORT pig FILE farm-targets-extra.cmake DESTINATION .) diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/MissingAppendixName-result.txt b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingAppendixName-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingAppendixName-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/MissingAppendixName-stderr.txt b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingAppendixName-stderr.txt new file mode 100644 index 0000000000..f63cc68562 --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingAppendixName-stderr.txt @@ -0,0 +1,5 @@ +CMake Error at MissingAppendixName.cmake:2 \(install\): + install CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO given APPENDIX directive for + export "foo", but no appendix name was provided\. +Call Stack \(most recent call first\): + CMakeLists\.txt:3 \(include\) diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/MissingAppendixName.cmake b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingAppendixName.cmake new file mode 100644 index 0000000000..08147e3313 --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingAppendixName.cmake @@ -0,0 +1,2 @@ +set(CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO foo:foo/a) +install(EXPORT foo FILE foo-targets.cmake DESTINATION .) diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/MissingExport-result.txt b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingExport-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingExport-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/MissingExport-stderr.txt b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingExport-stderr.txt new file mode 100644 index 0000000000..67e290bb8a --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingExport-stderr.txt @@ -0,0 +1,3 @@ +CMake Error: INSTALL\(PACKAGE_INFO\) given unknown export "foo" +CMake Error: INSTALL\(EXPORT\) given unknown export "foo" +CMake Generate step failed\. Build files cannot be regenerated correctly\. diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/MissingExport.cmake b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingExport.cmake new file mode 100644 index 0000000000..517af2217d --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingExport.cmake @@ -0,0 +1,2 @@ +set(CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO foo:foo) +install(EXPORT foo FILE foo-targets.cmake DESTINATION .) diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/MissingPackageName-result.txt b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingPackageName-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingPackageName-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/MissingPackageName-stderr.txt b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingPackageName-stderr.txt new file mode 100644 index 0000000000..99d4240b73 --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingPackageName-stderr.txt @@ -0,0 +1,5 @@ +CMake Error at MissingPackageName.cmake:2 \(install\): + install CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO missing package name for + export "foo"\. +Call Stack \(most recent call first\): + CMakeLists\.txt:3 \(include\) diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/MissingPackageName.cmake b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingPackageName.cmake new file mode 100644 index 0000000000..8489637454 --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/MissingPackageName.cmake @@ -0,0 +1,2 @@ +set(CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO foo:) +install(EXPORT foo FILE foo-targets.cmake DESTINATION .) diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/RunCMakeTest.cmake b/Tests/RunCMake/InstallExportsAsPackageInfo/RunCMakeTest.cmake new file mode 100644 index 0000000000..7f35c13204 --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/RunCMakeTest.cmake @@ -0,0 +1,22 @@ +include(RunCMake) + +# Test experimental gate +run_cmake(ExperimentalGate) +run_cmake(ExperimentalWarning) + +# Enable experimental feature and suppress warnings +set(RunCMake_TEST_OPTIONS + -Wno-dev + "-DCMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO:STRING=b80be207-778e-46ba-8080-b23bba22639e" + "-DCMAKE_EXPERIMENTAL_MAPPED_PACKAGE_INFO:STRING=ababa1b5-7099-495f-a9cd-e22d38f274f2" + ) + +# Test incorrect usage +run_cmake(MissingPackageName) +run_cmake(MissingAppendixName) +run_cmake(MissingExport) +run_cmake(BadDirective) + +# Test functionality +run_cmake(SampleExport) +run_cmake(LowerCase) diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/SampleExport-check.cmake b/Tests/RunCMake/InstallExportsAsPackageInfo/SampleExport-check.cmake new file mode 100644 index 0000000000..fdeeefa300 --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/SampleExport-check.cmake @@ -0,0 +1,19 @@ +include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake) + +set(out_dir "${RunCMake_BINARY_DIR}/SampleExport-build/CMakeFiles/Export/510c5684a4a8a792eadfb55bc9744983") + +file(READ "${out_dir}/farm.cps" content) +expect_value("${content}" "farm" "name") +expect_value("${content}" "interface" "components" "cow" "type") +expect_value("${content}" "1.2.3" "version") +expect_value("${content}" "1.1.0" "compat_version") +expect_value("${content}" "simple" "version_schema") +expect_value("${content}" "Apache-2.0" "license") +expect_value("${content}" "BSD-3-Clause" "default_license") +expect_array("${content}" 2 "configurations") +expect_value("${content}" "Small" "configurations" 0) +expect_value("${content}" "Large" "configurations" 1) + +file(READ "${out_dir}/farm-extra.cps" content) +expect_value("${content}" "farm" "name") +expect_value("${content}" "interface" "components" "pig" "type") diff --git a/Tests/RunCMake/InstallExportsAsPackageInfo/SampleExport.cmake b/Tests/RunCMake/InstallExportsAsPackageInfo/SampleExport.cmake new file mode 100644 index 0000000000..fedcec0ebc --- /dev/null +++ b/Tests/RunCMake/InstallExportsAsPackageInfo/SampleExport.cmake @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 4.2) + +project(farm VERSION 1.2.3 COMPAT_VERSION 1.1.0) + +set(CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO + cow:farm//cps + pig:farm/aextra/cps +) +set(cow_EXPORT_PACKAGE_INFO_VERSION @farm_VERSION@) +set(cow_EXPORT_PACKAGE_INFO_COMPAT_VERSION @farm_COMPAT_VERSION@) +set(cow_EXPORT_PACKAGE_INFO_VERSION_SCHEMA "simple") +set(cow_EXPORT_PACKAGE_INFO_LICENSE "Apache-2.0") +set(cow_EXPORT_PACKAGE_INFO_DEFAULT_LICENSE "BSD-3-Clause") +set(cow_EXPORT_PACKAGE_INFO_DEFAULT_CONFIGURATIONS "Small;Large") + +add_library(cow INTERFACE) +add_library(pig INTERFACE) + +install(TARGETS cow EXPORT cow) +install(TARGETS pig EXPORT pig) +install(EXPORT cow FILE farm-targets.cmake DESTINATION .) +install(EXPORT pig FILE farm-targets-extra.cmake DESTINATION .)