浏览代码

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
Cristian Adam 6 年之前
父节点
当前提交
26a99da206

+ 7 - 0
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;
 messages.  Some find-modules provide limited or no support for versioning;
 check the module documentation.
 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
 Full Signature and Config Mode
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 

+ 1 - 0
Help/manual/cmake-variables.7.rst

@@ -172,6 +172,7 @@ Variables that Change Behavior
    /variable/CMAKE_FIND_NO_INSTALL_PREFIX
    /variable/CMAKE_FIND_NO_INSTALL_PREFIX
    /variable/CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY
    /variable/CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY
    /variable/CMAKE_FIND_PACKAGE_NO_SYSTEM_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_RESOLVE_SYMLINKS
    /variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE
    /variable/CMAKE_FIND_PACKAGE_WARN_NO_MODULE
    /variable/CMAKE_FIND_ROOT_PATH
    /variable/CMAKE_FIND_ROOT_PATH

+ 6 - 0
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.

+ 27 - 0
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<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.

+ 3 - 0
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
 :command:`find_package` to warn when it implicitly assumes Config mode.  This
 helps developers enforce use of an explicit mode in all calls to
 helps developers enforce use of an explicit mode in all calls to
 :command:`find_package` within a project.
 :command:`find_package` within a project.
+
+This variable has no effect if :variable:`CMAKE_FIND_PACKAGE_PREFER_CONFIG` is
+set to ``TRUE``.

+ 53 - 42
Source/cmFindPackageCommand.cxx

@@ -499,50 +499,61 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args,
 
 
   // See if there is a Find<PackageName>.cmake module.
   // See if there is a Find<PackageName>.cmake module.
   bool loadedPackage = false;
   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;
       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;
+      }
     }
     }
   }
   }
 
 

+ 35 - 1
Tests/FindPackageTest/CMakeLists.txt

@@ -541,7 +541,41 @@ endif()
 set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
 set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
 unset(SortLib_VERSION)
 unset(SortLib_VERSION)
 
 
-
 unset(CMAKE_FIND_PACKAGE_SORT_ORDER)
 unset(CMAKE_FIND_PACKAGE_SORT_ORDER)
 unset(CMAKE_FIND_PACKAGE_SORT_DIRECTION)
 unset(CMAKE_FIND_PACKAGE_SORT_DIRECTION)
 set(CMAKE_PREFIX_PATH )
 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)

+ 1 - 0
Tests/FindPackageTest/PreferConfig/ABCConfig.cmake

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

+ 1 - 0
Tests/FindPackageTest/PreferConfig/FindABC.cmake

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