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
This commit is contained in:
Cristian Adam 2019-05-20 21:32:24 +02:00 committed by Brad King
parent c365243a3a
commit 26a99da206
9 changed files with 135 additions and 44 deletions

View File

@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -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

View File

@ -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.

View File

@ -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<pkg>.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<pkg>.cmake`` module before finding the developer's custom
built library.
Once this variable is set, it is the responsibility of the exported
``<pkg>Config.cmake`` files to provide the same result variables as the
``Find<pkg>.cmake`` modules so that dependent projects can use them
interchangeably.

View File

@ -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``.

View File

@ -499,50 +499,61 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args,
// See if there is a Find<PackageName>.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->FindPackageUsingConfigMode()) {
if (this->Makefile->IsOn("CMAKE_FIND_PACKAGE_PREFER_CONFIG")) {
if (this->UseConfigFiles && this->FindPackageUsingConfigMode()) {
loadedPackage = true;
} else if (this->FindPackageUsingModuleMode()) {
loadedPackage = true;
}
} 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;
}
}
}

View File

@ -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)

View File

@ -0,0 +1 @@
set(ABC_FOUND TRUE)

View File

@ -0,0 +1 @@
set(ABC_FOUND TRUE)