From c5231ba29e47101b772572f730af5b2bc82fbd53 Mon Sep 17 00:00:00 2001 From: Craig Scott Date: Sun, 14 Apr 2024 18:07:41 +1000 Subject: find_package: Save/restore PACKAGE_PREFIX_DIR Package configuration files generated by `configure_package_config_file` set this variable in `@PACKAGE_INIT@` and then use it later. There may be intervening calls to `find_package`, e.g., via `find_dependency`. If the loaded package also used `configure_package_config_file`, it may change the value of `PACKAGE_PREFIX_DIR`. Explicitly save and restore the value to avoid this. Fixes: #25827 --- Source/cmFindPackageCommand.cxx | 30 +++++++++++++++ .../CMakePackage/NestedConfigFile-stdout.txt | 6 +++ Tests/RunCMake/CMakePackage/NestedConfigFile.cmake | 43 ++++++++++++++++++++++ Tests/RunCMake/CMakePackage/RunCMakeTest.cmake | 2 + 4 files changed, 81 insertions(+) create mode 100644 Tests/RunCMake/CMakePackage/NestedConfigFile-stdout.txt create mode 100644 Tests/RunCMake/CMakePackage/NestedConfigFile.cmake diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 9b51b1a..3bfabd9 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -982,6 +982,36 @@ bool cmFindPackageCommand::InitialPass(std::vector const& args) return true; } + // Restore PACKAGE_PREFIX_DIR to its pre-call value when we return. If our + // caller is a file generated by configure_package_config_file(), and if + // the package we are about to load also has a config file created by that + // command, it will overwrite PACKAGE_PREFIX_DIR. We need to restore it in + // case something still refers to it in our caller's scope after we return. + class RestoreVariableOnLeavingScope + { + cmMakefile* makefile_; + cm::optional value_; + + public: + RestoreVariableOnLeavingScope(cmMakefile* makefile) + : makefile_(makefile) + { + cmValue v = makefile->GetDefinition("PACKAGE_PREFIX_DIR"); + if (v) { + value_ = *v; + } + } + ~RestoreVariableOnLeavingScope() + { + if (this->value_) { + makefile_->AddDefinition("PACKAGE_PREFIX_DIR", *value_); + } else { + makefile_->RemoveDefinition("PACKAGE_PREFIX_DIR"); + } + } + }; + RestoreVariableOnLeavingScope restorePackagePrefixDir(this->Makefile); + // Now choose what method(s) we will use to satisfy the request. Note that // we still want all the above checking of arguments, etc. regardless of the // method used. This will ensure ill-formed arguments are caught earlier, diff --git a/Tests/RunCMake/CMakePackage/NestedConfigFile-stdout.txt b/Tests/RunCMake/CMakePackage/NestedConfigFile-stdout.txt new file mode 100644 index 0000000..cdb3384 --- /dev/null +++ b/Tests/RunCMake/CMakePackage/NestedConfigFile-stdout.txt @@ -0,0 +1,6 @@ +(-- )?Before find_dependency: PACKAGE_PREFIX_DIR = .*/Tests/RunCMake/CMakePackage/NestedConfigFile-build/install_pkg_b +(-- )?Hello from pkg_a +(-- )?Leaving pkg_a-config\.cmake with PACKAGE_PREFIX_DIR = .*/Tests/RunCMake/CMakePackage/NestedConfigFile-build/install_pkg_a +(-- )?After find_dependency: PACKAGE_PREFIX_DIR = .*/Tests/RunCMake/CMakePackage/NestedConfigFile-build/install_pkg_b +(-- )?Hello from pkg_b +(-- )?Leaving pkg_b-config\.cmake with PACKAGE_PREFIX_DIR = .*/Tests/RunCMake/CMakePackage/NestedConfigFile-build/install_pkg_b diff --git a/Tests/RunCMake/CMakePackage/NestedConfigFile.cmake b/Tests/RunCMake/CMakePackage/NestedConfigFile.cmake new file mode 100644 index 0000000..2eeaebb --- /dev/null +++ b/Tests/RunCMake/CMakePackage/NestedConfigFile.cmake @@ -0,0 +1,43 @@ +set(CMAKE_INSTALL_DATADIR share) + +include(CMakePackageConfigHelpers) + +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/pkg_a-config.cmake.in [[ +@PACKAGE_INIT@ +include("@PACKAGE_CMAKE_INSTALL_DATADIR@/pkg_a_included.cmake") +message(STATUS "Leaving pkg_a-config.cmake with PACKAGE_PREFIX_DIR = ${PACKAGE_PREFIX_DIR}") +]]) +configure_package_config_file( + ${CMAKE_CURRENT_BINARY_DIR}/pkg_a-config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/install_pkg_a/pkg_a-config.cmake + INSTALL_DESTINATION . + PATH_VARS CMAKE_INSTALL_DATADIR +) +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/install_pkg_a/share/pkg_a_included.cmake + [[message(STATUS "Hello from pkg_a")]] +) + +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/pkg_b-config.cmake.in [[ +@PACKAGE_INIT@ +include(CMakeFindDependencyMacro) +message(STATUS "Before find_dependency: PACKAGE_PREFIX_DIR = ${PACKAGE_PREFIX_DIR}") +find_dependency(pkg_a NO_DEFAULT_PATH + PATHS "@CMAKE_CURRENT_BINARY_DIR@/install_pkg_a" +) +message(STATUS "After find_dependency: PACKAGE_PREFIX_DIR = ${PACKAGE_PREFIX_DIR}") +include("@PACKAGE_CMAKE_INSTALL_DATADIR@/pkg_b_included.cmake") +message(STATUS "Leaving pkg_b-config.cmake with PACKAGE_PREFIX_DIR = ${PACKAGE_PREFIX_DIR}") +]]) +configure_package_config_file( + ${CMAKE_CURRENT_BINARY_DIR}/pkg_b-config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/install_pkg_b/pkg_b-config.cmake + INSTALL_DESTINATION . + PATH_VARS CMAKE_INSTALL_DATADIR +) +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/install_pkg_b/share/pkg_b_included.cmake + [[message(STATUS "Hello from pkg_b")]] +) + +find_package(pkg_b REQUIRED NO_DEFAULT_PATH + PATHS ${CMAKE_CURRENT_BINARY_DIR}/install_pkg_b +) diff --git a/Tests/RunCMake/CMakePackage/RunCMakeTest.cmake b/Tests/RunCMake/CMakePackage/RunCMakeTest.cmake index 3b4bef5..c4a05e3 100644 --- a/Tests/RunCMake/CMakePackage/RunCMakeTest.cmake +++ b/Tests/RunCMake/CMakePackage/RunCMakeTest.cmake @@ -4,6 +4,8 @@ if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG) set(maybe_CMAKE_BUILD_TYPE -DCMAKE_BUILD_TYPE=Release) endif() +run_cmake_with_options(NestedConfigFile ${maybe_CMAKE_BUILD_TYPE}) + function(apple_export platform system_name archs sysroot) set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/apple-export-${platform}-build) string(REPLACE ";" "\\;" archs "${archs}") -- cgit v0.12