From 26a99da206526efb203d0e448d7e095a07bec2fd Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Mon, 20 May 2019 21:32:24 +0200 Subject: find_package: Add option to prefer Config mode Add a `CMAKE_FIND_PACKAGE_PREFER_CONFIG` variable to tell `find_package` calls to look for a package configuration file first even if a find module is available. Fixes: #16805, #19236 --- Help/command/find_package.rst | 7 ++ Help/manual/cmake-variables.7.rst | 1 + Help/release/dev/find-package-prefer-config.rst | 6 ++ Help/variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG.rst | 27 ++++++ .../variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst | 3 + Source/cmFindPackageCommand.cxx | 95 ++++++++++++---------- Tests/FindPackageTest/CMakeLists.txt | 36 +++++++- Tests/FindPackageTest/PreferConfig/ABCConfig.cmake | 1 + Tests/FindPackageTest/PreferConfig/FindABC.cmake | 1 + 9 files changed, 134 insertions(+), 43 deletions(-) create mode 100644 Help/release/dev/find-package-prefer-config.rst create mode 100644 Help/variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG.rst create mode 100644 Tests/FindPackageTest/PreferConfig/ABCConfig.cmake create mode 100644 Tests/FindPackageTest/PreferConfig/FindABC.cmake diff --git a/Help/command/find_package.rst b/Help/command/find_package.rst index eb44eb2..e5e5b2c 100644 --- a/Help/command/find_package.rst +++ b/Help/command/find_package.rst @@ -59,6 +59,13 @@ for finding the package, checking the version, and producing any needed messages. Some find-modules provide limited or no support for versioning; check the module documentation. +If the ``MODULE`` option is not specfied in the above signature, +CMake first searches for the package using Module mode. Then, if the +package is not found, it searches again using Config mode. A user +may set the variable :variable:`CMAKE_FIND_PACKAGE_PREFER_CONFIG` to +``TRUE`` to direct CMake first search using Config mode before falling +back to Module mode. + Full Signature and Config Mode ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index fd5e28f..1011ed2 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -172,6 +172,7 @@ Variables that Change Behavior /variable/CMAKE_FIND_NO_INSTALL_PREFIX /variable/CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY /variable/CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY + /variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG /variable/CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS /variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE /variable/CMAKE_FIND_ROOT_PATH diff --git a/Help/release/dev/find-package-prefer-config.rst b/Help/release/dev/find-package-prefer-config.rst new file mode 100644 index 0000000..377e8c5 --- /dev/null +++ b/Help/release/dev/find-package-prefer-config.rst @@ -0,0 +1,6 @@ +find-package-prefer-config +-------------------------- + +* Variable :variable:`CMAKE_FIND_PACKAGE_PREFER_CONFIG` was added to tell + :command:`find_package` calls to look for a package configuration + file first even if a find module is available. diff --git a/Help/variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG.rst b/Help/variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG.rst new file mode 100644 index 0000000..db658a1 --- /dev/null +++ b/Help/variable/CMAKE_FIND_PACKAGE_PREFER_CONFIG.rst @@ -0,0 +1,27 @@ +CMAKE_FIND_PACKAGE_PREFER_CONFIG +--------------------------------- + +Tell :command:`find_package` to try "Config" mode before "Module" mode if no +mode was specified. + +The command :command:`find_package` operates without an explicit mode when +the reduced signature is used without the ``MODULE`` option. In this case, +by default, CMake first tries Module mode by searching for a +``Find.cmake`` module. If it fails, CMake then searches for the package +using Config mode. + +Set ``CMAKE_FIND_PACKAGE_PREFER_CONFIG`` to ``TRUE`` to tell +:command:`find_package` to first search using Config mode before falling back +to Module mode. + +This variable may be useful when a developer has compiled a custom version of +a common library and wishes to link it to a dependent project. If this +variable is set to ``TRUE``, it would prevent a dependent project's call +to :command:`find_package` from selecting the default library located by the +system's ``Find.cmake`` module before finding the developer's custom +built library. + +Once this variable is set, it is the responsibility of the exported +``Config.cmake`` files to provide the same result variables as the +``Find.cmake`` modules so that dependent projects can use them +interchangeably. diff --git a/Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst b/Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst index f1116bb..5c4f23a 100644 --- a/Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst +++ b/Help/variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE.rst @@ -17,3 +17,6 @@ Set ``CMAKE_FIND_PACKAGE_WARN_NO_MODULE`` to ``TRUE`` to tell :command:`find_package` to warn when it implicitly assumes Config mode. This helps developers enforce use of an explicit mode in all calls to :command:`find_package` within a project. + +This variable has no effect if :variable:`CMAKE_FIND_PACKAGE_PREFER_CONFIG` is +set to ``TRUE``. diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 5310a1b..8eefaa7 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -499,50 +499,61 @@ bool cmFindPackageCommand::InitialPass(std::vector const& args, // See if there is a Find.cmake module. bool loadedPackage = false; - if (this->UseFindModules && this->FindPackageUsingModuleMode()) { - loadedPackage = true; - } else { - // Handle CMAKE_FIND_PACKAGE_WARN_NO_MODULE (warn when CONFIG mode is - // implicitly assumed) - if (this->UseFindModules && this->UseConfigFiles && - this->Makefile->IsOn("CMAKE_FIND_PACKAGE_WARN_NO_MODULE")) { - std::ostringstream aw; - if (this->RequiredCMakeVersion >= CMake_VERSION_ENCODE(2, 8, 8)) { - aw << "find_package called without either MODULE or CONFIG option and " - "no Find" - << this->Name - << ".cmake module is in CMAKE_MODULE_PATH. " - "Add MODULE to exclusively request Module mode and fail if " - "Find" - << this->Name - << ".cmake is missing. " - "Add CONFIG to exclusively request Config mode and search for a " - "package configuration file provided by " - << this->Name << " (" << this->Name << "Config.cmake or " - << cmSystemTools::LowerCase(this->Name) << "-config.cmake). "; - } else { - aw << "find_package called without NO_MODULE option and no " - "Find" - << this->Name - << ".cmake module is in CMAKE_MODULE_PATH. " - "Add NO_MODULE to exclusively request Config mode and search " - "for a " - "package configuration file provided by " - << this->Name << " (" << this->Name << "Config.cmake or " - << cmSystemTools::LowerCase(this->Name) - << "-config.cmake). " - "Otherwise make Find" - << this->Name - << ".cmake available in " - "CMAKE_MODULE_PATH."; - } - aw << "\n" - "(Variable CMAKE_FIND_PACKAGE_WARN_NO_MODULE enabled this " - "warning.)"; - this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, aw.str()); + if (this->Makefile->IsOn("CMAKE_FIND_PACKAGE_PREFER_CONFIG")) { + if (this->UseConfigFiles && this->FindPackageUsingConfigMode()) { + loadedPackage = true; + } else if (this->FindPackageUsingModuleMode()) { + loadedPackage = true; } - if (this->FindPackageUsingConfigMode()) { + } else { + if (this->UseFindModules && this->FindPackageUsingModuleMode()) { loadedPackage = true; + } else { + // Handle CMAKE_FIND_PACKAGE_WARN_NO_MODULE (warn when CONFIG mode is + // implicitly assumed) + if (this->UseFindModules && this->UseConfigFiles && + this->Makefile->IsOn("CMAKE_FIND_PACKAGE_WARN_NO_MODULE")) { + std::ostringstream aw; + if (this->RequiredCMakeVersion >= CMake_VERSION_ENCODE(2, 8, 8)) { + aw << "find_package called without either MODULE or CONFIG option " + "and " + "no Find" + << this->Name + << ".cmake module is in CMAKE_MODULE_PATH. " + "Add MODULE to exclusively request Module mode and fail if " + "Find" + << this->Name + << ".cmake is missing. " + "Add CONFIG to exclusively request Config mode and search for " + "a " + "package configuration file provided by " + << this->Name << " (" << this->Name << "Config.cmake or " + << cmSystemTools::LowerCase(this->Name) << "-config.cmake). "; + } else { + aw << "find_package called without NO_MODULE option and no " + "Find" + << this->Name + << ".cmake module is in CMAKE_MODULE_PATH. " + "Add NO_MODULE to exclusively request Config mode and search " + "for a " + "package configuration file provided by " + << this->Name << " (" << this->Name << "Config.cmake or " + << cmSystemTools::LowerCase(this->Name) + << "-config.cmake). " + "Otherwise make Find" + << this->Name + << ".cmake available in " + "CMAKE_MODULE_PATH."; + } + aw << "\n" + "(Variable CMAKE_FIND_PACKAGE_WARN_NO_MODULE enabled this " + "warning.)"; + this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, aw.str()); + } + + if (this->FindPackageUsingConfigMode()) { + loadedPackage = true; + } } } diff --git a/Tests/FindPackageTest/CMakeLists.txt b/Tests/FindPackageTest/CMakeLists.txt index 6c876a7..8802b73 100644 --- a/Tests/FindPackageTest/CMakeLists.txt +++ b/Tests/FindPackageTest/CMakeLists.txt @@ -541,7 +541,41 @@ endif() set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE) unset(SortLib_VERSION) - unset(CMAKE_FIND_PACKAGE_SORT_ORDER) unset(CMAKE_FIND_PACKAGE_SORT_DIRECTION) set(CMAKE_PREFIX_PATH ) + +############################################################################ +##Test FIND_PACKAGE CMAKE_FIND_PACKAGE_PREFER_CONFIG + +set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR}/PreferConfig) +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/PreferConfig) + +# prefer module mode +set(CMAKE_FIND_PACKAGE_PREFER_CONFIG OFF) +unset(ABC_FOUND) +unset(ABC_CONFIG) + +find_package(ABC) +if(NOT ABC_FOUND) + message(SEND_ERROR "Did not find ABC package") +endif() +if(ABC_CONFIG) + message(SEND_ERROR "Incorrectly found ABC in CONFIG mode, expected to find it with MODULE mode") +endif() + +# Now prefer config mode +set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON) +unset(ABC_FOUND) +unset(ABC_CONFIG) + +find_package(ABC) +if(NOT ABC_FOUND) + message(SEND_ERROR "Did not find ABC package") +endif() +if(NOT ABC_CONFIG) + message(SEND_ERROR "Incorrectly found ABC in MODULE mode, expected to find it with CONFIG mode") +endif() + +set(CMAKE_FIND_PACKAGE_PREFER_CONFIG OFF) +set(CMAKE_PREFIX_PATH) diff --git a/Tests/FindPackageTest/PreferConfig/ABCConfig.cmake b/Tests/FindPackageTest/PreferConfig/ABCConfig.cmake new file mode 100644 index 0000000..281a5cd --- /dev/null +++ b/Tests/FindPackageTest/PreferConfig/ABCConfig.cmake @@ -0,0 +1 @@ +set(ABC_FOUND TRUE) diff --git a/Tests/FindPackageTest/PreferConfig/FindABC.cmake b/Tests/FindPackageTest/PreferConfig/FindABC.cmake new file mode 100644 index 0000000..281a5cd --- /dev/null +++ b/Tests/FindPackageTest/PreferConfig/FindABC.cmake @@ -0,0 +1 @@ +set(ABC_FOUND TRUE) -- cgit v0.12