Переглянути джерело

find_package: Use PackageName_ROOT variables as search prefixes

This feature was originally added by commit v3.9.0-rc1~71^2~2 (find_*:
Add a new PackageRoot search path group, 2017-05-03) and documented by
commit v3.9.0-rc1~71^2 (find_*: Add docs for PackageRoot search path
group, 2017-05-03).  However, we had to disable the feature and remove
the documentation in commit v3.9.1~2^2 (find_*: Disable the PACKAGE_ROOT
search path group for CMake 3.9, 2017-08-08) due to breaking projects
that used `PackageName_ROOT` variables themselves.

Add policy `CMP0074` to restore the `PackageName_ROOT` variable behavior
in a compatible way.  Also revise the stack of root paths to store the
paths themselves rather than the package names.  This way the policy can
be considered at the `find_package` call site instead of individual
`find_` calls inside a find module.

Co-Author: Chuck Atkins <[email protected]>
Issue: #17144
Brad King 7 роки тому
батько
коміт
eb35d8884b

+ 23 - 6
Help/command/FIND_XXX.txt

@@ -16,6 +16,7 @@ The general signature is:
              [PATH_SUFFIXES suffix1 [suffix2 ...]]
              [DOC "cache documentation string"]
              [NO_DEFAULT_PATH]
+             [NO_PACKAGE_ROOT_PATH]
              [NO_CMAKE_PATH]
              [NO_CMAKE_ENVIRONMENT_PATH]
              [NO_SYSTEM_ENVIRONMENT_PATH]
@@ -60,6 +61,10 @@ If ``NO_DEFAULT_PATH`` is specified, then no additional paths are
 added to the search.
 If ``NO_DEFAULT_PATH`` is not specified, the search process is as follows:
 
+.. |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX_SUBDIR| replace::
+   |prefix_XXX_SUBDIR| for each ``<prefix>`` in ``PackageName_ROOT`` if called
+   from within a find module
+
 .. |CMAKE_PREFIX_PATH_XXX_SUBDIR| replace::
    |prefix_XXX_SUBDIR| for each ``<prefix>`` in :variable:`CMAKE_PREFIX_PATH`
 
@@ -71,7 +76,19 @@ If ``NO_DEFAULT_PATH`` is not specified, the search process is as follows:
    |prefix_XXX_SUBDIR| for each ``<prefix>`` in
    :variable:`CMAKE_SYSTEM_PREFIX_PATH`
 
-1. Search paths specified in cmake-specific cache variables.
+1. If called from within a find module, search prefix paths unique to the
+   current package being found.  Specifically look in the ``PackageName_ROOT``
+   CMake and environment variables.  The package root variables are maintained
+   as a stack so if called from nested find modules, root paths from the
+   parent's find module will be searchd after paths from the current module,
+   i.e. ``CurrentPackage_ROOT``, ``ENV{CurrentPackage_ROOT}``,
+   ``ParentPackage_ROOT``, ``ENV{ParentPacakge_ROOT}``, etc.
+   This can be skipped if ``NO_PACKAGE_ROOT_PATH`` is passed.
+   See policy :policy:`CMP0074`.
+
+   * |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX|
+
+2. Search paths specified in cmake-specific cache variables.
    These are intended to be used on the command line with a ``-DVAR=value``.
    The values are interpreted as :ref:`;-lists <CMake Language Lists>`.
    This can be skipped if ``NO_CMAKE_PATH`` is passed.
@@ -80,7 +97,7 @@ If ``NO_DEFAULT_PATH`` is not specified, the search process is as follows:
    * |CMAKE_XXX_PATH|
    * |CMAKE_XXX_MAC_PATH|
 
-2. Search paths specified in cmake-specific environment variables.
+3. Search paths specified in cmake-specific environment variables.
    These are intended to be set in the user's shell configuration,
    and therefore use the host's native path separator
    (``;`` on Windows and ``:`` on UNIX).
@@ -90,17 +107,17 @@ If ``NO_DEFAULT_PATH`` is not specified, the search process is as follows:
    * |CMAKE_XXX_PATH|
    * |CMAKE_XXX_MAC_PATH|
 
-3. Search the paths specified by the ``HINTS`` option.
+4. Search the paths specified by the ``HINTS`` option.
    These should be paths computed by system introspection, such as a
    hint provided by the location of another item already found.
    Hard-coded guesses should be specified with the ``PATHS`` option.
 
-4. Search the standard system environment variables.
+5. Search the standard system environment variables.
    This can be skipped if ``NO_SYSTEM_ENVIRONMENT_PATH`` is an argument.
 
    * |SYSTEM_ENVIRONMENT_PATH_XXX|
 
-5. Search cmake variables defined in the Platform files
+6. Search cmake variables defined in the Platform files
    for the current system.  This can be skipped if ``NO_CMAKE_SYSTEM_PATH``
    is passed.
 
@@ -108,7 +125,7 @@ If ``NO_DEFAULT_PATH`` is not specified, the search process is as follows:
    * |CMAKE_SYSTEM_XXX_PATH|
    * |CMAKE_SYSTEM_XXX_MAC_PATH|
 
-6. Search the paths specified by the PATHS option
+7. Search the paths specified by the PATHS option
    or in the short-hand version of the command.
    These are typically hard-coded guesses.
 

+ 3 - 0
Help/command/find_file.rst

@@ -8,6 +8,9 @@ find_file
 .. |prefix_XXX_SUBDIR| replace:: ``<prefix>/include``
 .. |entry_XXX_SUBDIR| replace:: ``<entry>/include``
 
+.. |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX| replace::
+   ``<prefix>/include/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE`
+   is set, and |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX_SUBDIR|
 .. |CMAKE_PREFIX_PATH_XXX| replace::
    ``<prefix>/include/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE`
    is set, and |CMAKE_PREFIX_PATH_XXX_SUBDIR|

+ 3 - 0
Help/command/find_library.rst

@@ -8,6 +8,9 @@ find_library
 .. |prefix_XXX_SUBDIR| replace:: ``<prefix>/lib``
 .. |entry_XXX_SUBDIR| replace:: ``<entry>/lib``
 
+.. |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX| replace::
+   ``<prefix>/lib/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE` is set,
+   and |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX_SUBDIR|
 .. |CMAKE_PREFIX_PATH_XXX| replace::
    ``<prefix>/lib/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE` is set,
    and |CMAKE_PREFIX_PATH_XXX_SUBDIR|

+ 16 - 8
Help/command/find_package.rst

@@ -64,6 +64,7 @@ The complete Config mode command signature is::
                [PATHS path1 [path2 ... ]]
                [PATH_SUFFIXES suffix1 [suffix2 ...]]
                [NO_DEFAULT_PATH]
+               [NO_PACKAGE_ROOT_PATH]
                [NO_CMAKE_PATH]
                [NO_CMAKE_ENVIRONMENT_PATH]
                [NO_SYSTEM_ENVIRONMENT_PATH]
@@ -249,7 +250,14 @@ The set of installation prefixes is constructed using the following
 steps.  If ``NO_DEFAULT_PATH`` is specified all ``NO_*`` options are
 enabled.
 
-1. Search paths specified in cmake-specific cache variables.  These
+1. Search paths specified in the ``PackageName_ROOT`` CMake and environment
+   variables.  The package root variables are maintained as a stack so if
+   called from within a find module, root paths from the parent's find
+   module will also be searched after paths for the current package.
+   This can be skipped if ``NO_PACKAGE_ROOT_PATH`` is passed.
+   See policy :policy:`CMP0074`.
+
+2. Search paths specified in cmake-specific cache variables.  These
    are intended to be used on the command line with a ``-DVAR=value``.
    The values are interpreted as :ref:`;-lists <CMake Language Lists>`.
    This can be skipped if ``NO_CMAKE_PATH`` is passed::
@@ -258,7 +266,7 @@ enabled.
      CMAKE_FRAMEWORK_PATH
      CMAKE_APPBUNDLE_PATH
 
-2. Search paths specified in cmake-specific environment variables.
+3. Search paths specified in cmake-specific environment variables.
    These are intended to be set in the user's shell configuration,
    and therefore use the host's native path separator
    (``;`` on Windows and ``:`` on UNIX).
@@ -269,26 +277,26 @@ enabled.
      CMAKE_FRAMEWORK_PATH
      CMAKE_APPBUNDLE_PATH
 
-3. Search paths specified by the ``HINTS`` option.  These should be paths
+4. Search paths specified by the ``HINTS`` option.  These should be paths
    computed by system introspection, such as a hint provided by the
    location of another item already found.  Hard-coded guesses should
    be specified with the ``PATHS`` option.
 
-4. Search the standard system environment variables.  This can be
+5. Search the standard system environment variables.  This can be
    skipped if ``NO_SYSTEM_ENVIRONMENT_PATH`` is passed.  Path entries
    ending in ``/bin`` or ``/sbin`` are automatically converted to their
    parent directories::
 
      PATH
 
-5. Search paths stored in the CMake :ref:`User Package Registry`.
+6. Search paths stored in the CMake :ref:`User Package Registry`.
    This can be skipped if ``NO_CMAKE_PACKAGE_REGISTRY`` is passed or by
    setting the :variable:`CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY`
    to ``TRUE``.
    See the :manual:`cmake-packages(7)` manual for details on the user
    package registry.
 
-6. Search cmake variables defined in the Platform files for the
+7. Search cmake variables defined in the Platform files for the
    current system.  This can be skipped if ``NO_CMAKE_SYSTEM_PATH`` is
    passed::
 
@@ -296,14 +304,14 @@ enabled.
      CMAKE_SYSTEM_FRAMEWORK_PATH
      CMAKE_SYSTEM_APPBUNDLE_PATH
 
-7. Search paths stored in the CMake :ref:`System Package Registry`.
+8. Search paths stored in the CMake :ref:`System Package Registry`.
    This can be skipped if ``NO_CMAKE_SYSTEM_PACKAGE_REGISTRY`` is passed
    or by setting the
    :variable:`CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY` to ``TRUE``.
    See the :manual:`cmake-packages(7)` manual for details on the system
    package registry.
 
-8. Search paths specified by the ``PATHS`` option.  These are typically
+9. Search paths specified by the ``PATHS`` option.  These are typically
    hard-coded guesses.
 
 .. |FIND_XXX| replace:: find_package

+ 3 - 0
Help/command/find_path.rst

@@ -8,6 +8,9 @@ find_path
 .. |prefix_XXX_SUBDIR| replace:: ``<prefix>/include``
 .. |entry_XXX_SUBDIR| replace:: ``<entry>/include``
 
+.. |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX| replace::
+   ``<prefix>/include/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE`
+   is set, and |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX_SUBDIR|
 .. |CMAKE_PREFIX_PATH_XXX| replace::
    ``<prefix>/include/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE`
    is set, and |CMAKE_PREFIX_PATH_XXX_SUBDIR|

+ 2 - 0
Help/command/find_program.rst

@@ -8,6 +8,8 @@ find_program
 .. |prefix_XXX_SUBDIR| replace:: ``<prefix>/[s]bin``
 .. |entry_XXX_SUBDIR| replace:: ``<entry>/[s]bin``
 
+.. |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX| replace::
+   |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX_SUBDIR|
 .. |CMAKE_PREFIX_PATH_XXX| replace::
    |CMAKE_PREFIX_PATH_XXX_SUBDIR|
 .. |CMAKE_XXX_PATH| replace:: :variable:`CMAKE_PROGRAM_PATH`

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

@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.12
 .. toctree::
    :maxdepth: 1
 
+   CMP0074: find_package uses PackageName_ROOT variables. </policy/CMP0074>
    CMP0073: Do not produce legacy _LIB_DEPENDS cache entries. </policy/CMP0073>
 
 Policies Introduced by CMake 3.11

+ 22 - 0
Help/policy/CMP0074.rst

@@ -0,0 +1,22 @@
+CMP0074
+-------
+
+:command:`find_package` uses ``PackageName_ROOT`` variables.
+
+In CMake 3.12 and above the ``find_package(PackageName)`` command now searches
+a prefix specified by a ``PackageName_ROOT`` CMake or environment variable.
+Package roots are maintained as a stack so nested calls to all ``find_*``
+commands inside find modules also search the roots as prefixes.  This policy
+provides compatibility with projects that have not been updated to avoid using
+``PackageName_ROOT`` variables for other purposes.
+
+The ``OLD`` behavior for this policy is to ignore ``PackageName_ROOT``
+variables.  The ``NEW`` behavior for this policy is to use ``PackageName_ROOT``
+variables.
+
+This policy was introduced in CMake version 3.12.  CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt

+ 8 - 0
Help/release/dev/find-package_root-restore.rst

@@ -0,0 +1,8 @@
+find-package_root-restore
+-------------------------
+
+* The :command:`find_package` command now searches a prefix specified by
+  a ``PackageName_ROOT`` CMake or environment variable.  Package roots are
+  maintained as a stack so nested calls to all ``find_*`` commands inside
+  find modules also search the roots as prefixes.
+  See policy :policy:`CMP0074`.

+ 6 - 12
Source/cmFindBase.cxx

@@ -67,8 +67,6 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
   }
   this->AlreadyInCache = false;
 
-  this->SelectDefaultNoPackageRootPath();
-
   // Find the current root path mode.
   this->SelectDefaultRootPathMode();
 
@@ -206,16 +204,12 @@ void cmFindBase::FillPackageRootPath()
 {
   cmSearchPath& paths = this->LabeledPaths[PathLabel::PackageRoot];
 
-  // Add package specific search prefixes
-  // NOTE: This should be using const_reverse_iterator but HP aCC and
-  //       Oracle sunCC both currently have standard library issues
-  //       with the reverse iterator APIs.
-  for (std::deque<std::string>::reverse_iterator pkg =
-         this->Makefile->FindPackageModuleStack.rbegin();
-       pkg != this->Makefile->FindPackageModuleStack.rend(); ++pkg) {
-    std::string varName = *pkg + "_ROOT";
-    paths.AddCMakePrefixPath(varName);
-    paths.AddEnvPrefixPath(varName);
+  // Add the PACKAGE_ROOT_PATH from each enclosing find_package call.
+  for (std::deque<std::vector<std::string>>::const_reverse_iterator pkgPaths =
+         this->Makefile->FindPackageRootPathStack.rbegin();
+       pkgPaths != this->Makefile->FindPackageRootPathStack.rend();
+       ++pkgPaths) {
+    paths.AddPrefixPaths(*pkgPaths);
   }
 
   paths.AddSuffixes(this->SearchPathSuffixes);

+ 0 - 7
Source/cmFindCommon.cxx

@@ -88,13 +88,6 @@ void cmFindCommon::InitializeSearchPathGroups()
     std::make_pair(PathLabel::Guess, cmSearchPath(this)));
 }
 
-void cmFindCommon::SelectDefaultNoPackageRootPath()
-{
-  if (!this->Makefile->IsOn("__UNDOCUMENTED_CMAKE_FIND_PACKAGE_ROOT")) {
-    this->NoPackageRootPath = true;
-  }
-}
-
 void cmFindCommon::SelectDefaultRootPathMode()
 {
   // Check the policy variable for this find command type.

+ 0 - 3
Source/cmFindCommon.h

@@ -84,9 +84,6 @@ protected:
   /** Compute final search path list (reroot + trailing slash).  */
   void ComputeFinalPaths();
 
-  /** Decide whether to enable the PACKAGE_ROOT search entries.  */
-  void SelectDefaultNoPackageRootPath();
-
   /** Compute the current default root path mode.  */
   void SelectDefaultRootPathMode();
 

+ 42 - 16
Source/cmFindPackageCommand.cxx

@@ -21,6 +21,7 @@
 
 #include "cmAlgorithms.h"
 #include "cmMakefile.h"
+#include "cmPolicies.h"
 #include "cmSearchPath.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
@@ -209,8 +210,6 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args,
     this->SortDirection = strcmp(sd, "ASC") == 0 ? Asc : Dec;
   }
 
-  this->SelectDefaultNoPackageRootPath();
-
   // Find the current root path mode.
   this->SelectDefaultRootPathMode();
 
@@ -454,6 +453,38 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args,
     return true;
   }
 
+  {
+    // Allocate a PACKAGE_ROOT_PATH for the current find_package call.
+    this->Makefile->FindPackageRootPathStack.emplace_back();
+    std::vector<std::string>& rootPaths =
+      *this->Makefile->FindPackageRootPathStack.rbegin();
+
+    // Add root paths from <PackageName>_ROOT CMake and environment variables,
+    // subject to CMP0074.
+    switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0074)) {
+      case cmPolicies::WARN:
+        this->Makefile->MaybeWarnCMP0074(this->Name);
+        CM_FALLTHROUGH;
+      case cmPolicies::OLD:
+        // OLD behavior is to ignore the <pkg>_ROOT variables.
+        break;
+      case cmPolicies::REQUIRED_IF_USED:
+      case cmPolicies::REQUIRED_ALWAYS:
+        this->Makefile->IssueMessage(
+          cmake::FATAL_ERROR,
+          cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0074));
+        break;
+      case cmPolicies::NEW: {
+        // NEW behavior is to honor the <pkg>_ROOT variables.
+        std::string const rootVar = this->Name + "_ROOT";
+        if (const char* pkgRoot = this->Makefile->GetDefinition(rootVar)) {
+          cmSystemTools::ExpandListArgument(pkgRoot, rootPaths, false);
+        }
+        cmSystemTools::GetPath(rootPaths, rootVar.c_str());
+      } break;
+    }
+  }
+
   this->SetModuleVariables(components);
 
   // See if there is a Find<package>.cmake module.
@@ -589,9 +620,6 @@ void cmFindPackageCommand::SetModuleVariables(const std::string& components)
     exact += "_FIND_VERSION_EXACT";
     this->AddFindDefinition(exact, this->VersionExact ? "1" : "0");
   }
-
-  // Push on to the package stack
-  this->Makefile->FindPackageModuleStack.push_back(this->Name);
 }
 
 void cmFindPackageCommand::AddFindDefinition(const std::string& var,
@@ -1076,7 +1104,7 @@ void cmFindPackageCommand::AppendSuccessInformation()
   this->RestoreFindDefinitions();
 
   // Pop the package stack
-  this->Makefile->FindPackageModuleStack.pop_back();
+  this->Makefile->FindPackageRootPathStack.pop_back();
 }
 
 void cmFindPackageCommand::ComputePrefixes()
@@ -1116,16 +1144,14 @@ void cmFindPackageCommand::FillPrefixesPackageRoot()
 {
   cmSearchPath& paths = this->LabeledPaths[PathLabel::PackageRoot];
 
-  // Add package specific search prefixes
-  // NOTE: This should be using const_reverse_iterator but HP aCC and
-  //       Oracle sunCC both currently have standard library issues
-  //       with the reverse iterator APIs.
-  for (std::deque<std::string>::reverse_iterator pkg =
-         this->Makefile->FindPackageModuleStack.rbegin();
-       pkg != this->Makefile->FindPackageModuleStack.rend(); ++pkg) {
-    std::string varName = *pkg + "_ROOT";
-    paths.AddCMakePath(varName);
-    paths.AddEnvPath(varName);
+  // Add the PACKAGE_ROOT_PATH from each enclosing find_package call.
+  for (std::deque<std::vector<std::string>>::const_reverse_iterator pkgPaths =
+         this->Makefile->FindPackageRootPathStack.rbegin();
+       pkgPaths != this->Makefile->FindPackageRootPathStack.rend();
+       ++pkgPaths) {
+    for (std::string const& path : *pkgPaths) {
+      paths.AddPath(path);
+    }
   }
 }
 

+ 20 - 0
Source/cmMakefile.cxx

@@ -158,6 +158,26 @@ bool cmMakefile::CheckCMP0037(std::string const& targetName,
   return true;
 }
 
+void cmMakefile::MaybeWarnCMP0074(std::string const& pkg)
+{
+  // Warn if a <pkg>_ROOT variable we may use is set.
+  std::string const varName = pkg + "_ROOT";
+  bool const haveVar = this->GetDefinition(varName) != nullptr;
+  bool const haveEnv = cmSystemTools::HasEnv(varName);
+  if ((haveVar || haveEnv) && this->WarnedCMP0074.insert(varName).second) {
+    std::ostringstream w;
+    w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0074) << "\n";
+    if (haveVar) {
+      w << "CMake variable " << varName << " is set.\n";
+    }
+    if (haveEnv) {
+      w << "Environment variable " << varName << " is set.\n";
+    }
+    w << "For compatibility, CMake is ignoring the variable.";
+    this->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+  }
+}
+
 cmStringRange cmMakefile::GetIncludeDirectoriesEntries() const
 {
   return this->StateSnapshot.GetDirectory().GetIncludeDirectoriesEntries();

+ 6 - 3
Source/cmMakefile.h

@@ -832,9 +832,11 @@ public:
   void RemoveExportBuildFileGeneratorCMP0024(cmExportBuildFileGenerator* gen);
   void AddExportBuildFileGenerator(cmExportBuildFileGenerator* gen);
 
-  // Maintain a stack of package names to determine the depth of find modules
-  // we are currently being called with
-  std::deque<std::string> FindPackageModuleStack;
+  // Maintain a stack of package roots to allow nested PACKAGE_ROOT_PATH
+  // searches
+  std::deque<std::vector<std::string>> FindPackageRootPathStack;
+
+  void MaybeWarnCMP0074(std::string const& pkg);
 
 protected:
   // add link libraries and directories to the target
@@ -1001,6 +1003,7 @@ private:
   bool WarnUnused;
   bool CheckSystemVars;
   bool CheckCMP0000;
+  std::set<std::string> WarnedCMP0074;
   bool IsSourceFileTryCompile;
   mutable bool SuppressWatches;
 };

+ 3 - 1
Source/cmPolicies.h

@@ -217,7 +217,9 @@ class cmMakefile;
          cmPolicies::WARN)                                                    \
   SELECT(POLICY, CMP0073,                                                     \
          "Do not produce legacy _LIB_DEPENDS cache entries.", 3, 12, 0,       \
-         cmPolicies::WARN)
+         cmPolicies::WARN)                                                    \
+  SELECT(POLICY, CMP0074, "find_package uses PackageName_ROOT variables.", 3, \
+         12, 0, cmPolicies::WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \

+ 2 - 2
Source/cmSearchPath.h

@@ -39,10 +39,10 @@ public:
   void AddCMakePrefixPath(const std::string& variable);
   void AddEnvPrefixPath(const std::string& variable, bool stripBin = false);
   void AddSuffixes(const std::vector<std::string>& suffixes);
-
-protected:
   void AddPrefixPaths(const std::vector<std::string>& paths,
                       const char* base = nullptr);
+
+protected:
   void AddPathInternal(const std::string& path, const char* base = nullptr);
 
   cmFindCommon* FC;

+ 12 - 0
Tests/RunCMake/find_package/CMP0074-OLD-stderr.txt

@@ -0,0 +1,12 @@
+----------
+Foo_ROOT      :<base>/foo/cmake_root
+ENV{Foo_ROOT} :<base>/foo/env_root
+
+find_package\(Foo\)
+FOO_TEST_FILE_FOO :FOO_TEST_FILE_FOO-NOTFOUND
+FOO_TEST_FILE_ZOT :FOO_TEST_FILE_ZOT-NOTFOUND
+FOO_TEST_PATH_FOO :FOO_TEST_PATH_FOO-NOTFOUND
+FOO_TEST_PATH_ZOT :FOO_TEST_PATH_ZOT-NOTFOUND
+FOO_TEST_PROG_FOO :FOO_TEST_PROG_FOO-NOTFOUND
+
+----------

+ 2 - 0
Tests/RunCMake/find_package/CMP0074-OLD.cmake

@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0074 OLD)
+include(CMP0074-common.cmake)

+ 28 - 0
Tests/RunCMake/find_package/CMP0074-WARN-stderr.txt

@@ -0,0 +1,28 @@
+----------
+Foo_ROOT      :<base>/foo/cmake_root
+ENV{Foo_ROOT} :<base>/foo/env_root
++
+CMake Warning \(dev\) at CMP0074-common.cmake:[0-9]+ \(find_package\):
+  Policy CMP0074 is not set: find_package uses PackageName_ROOT variables.
+  Run "cmake --help-policy CMP0074" for policy details.  Use the cmake_policy
+  command to set the policy and suppress this warning.
+
+  CMake variable Foo_ROOT is set.
+
+  Environment variable Foo_ROOT is set.
+
+  For compatibility, CMake is ignoring the variable.
+Call Stack \(most recent call first\):
+  CMP0074-common.cmake:[0-9]+ \(RunPackageRootTest\)
+  CMP0074-WARN.cmake:[0-9]+ \(include\)
+  CMakeLists.txt:[0-9]+ \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
++
+find_package\(Foo\)
+FOO_TEST_FILE_FOO :FOO_TEST_FILE_FOO-NOTFOUND
+FOO_TEST_FILE_ZOT :FOO_TEST_FILE_ZOT-NOTFOUND
+FOO_TEST_PATH_FOO :FOO_TEST_PATH_FOO-NOTFOUND
+FOO_TEST_PATH_ZOT :FOO_TEST_PATH_ZOT-NOTFOUND
+FOO_TEST_PROG_FOO :FOO_TEST_PROG_FOO-NOTFOUND
+
+----------

+ 2 - 0
Tests/RunCMake/find_package/CMP0074-WARN.cmake

@@ -0,0 +1,2 @@
+# (do not set CMP0074)
+include(CMP0074-common.cmake)

+ 46 - 0
Tests/RunCMake/find_package/CMP0074-common.cmake

@@ -0,0 +1,46 @@
+# (includer selects CMP0074)
+cmake_policy(SET CMP0057 NEW)
+list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/PackageRoot)
+set(PackageRoot_BASE ${CMAKE_CURRENT_SOURCE_DIR}/PackageRoot)
+
+function(PrintPath label path)
+  string(REPLACE "${PackageRoot_BASE}" "<base>" out "${path}")
+  message("${label}${out}")
+endfunction()
+
+macro(CleanUpPackageRootTest)
+  unset(Foo_ROOT)
+  unset(ENV{Foo_ROOT})
+  unset(FOO_TEST_FILE_FOO)
+  unset(FOO_TEST_FILE_ZOT)
+  unset(FOO_TEST_PATH_FOO)
+  unset(FOO_TEST_PATH_ZOT)
+  unset(FOO_TEST_PROG_FOO)
+  unset(FOO_TEST_FILE_FOO CACHE)
+  unset(FOO_TEST_FILE_ZOT CACHE)
+  unset(FOO_TEST_PATH_FOO CACHE)
+  unset(FOO_TEST_PATH_ZOT CACHE)
+  unset(FOO_TEST_PROG_FOO CACHE)
+endmacro()
+
+macro(RunPackageRootTest)
+  message("----------")
+  PrintPath("Foo_ROOT      :" "${Foo_ROOT}")
+  PrintPath("ENV{Foo_ROOT} :" "$ENV{Foo_ROOT}")
+  message("")
+
+  find_package(Foo)
+  message("find_package(Foo)")
+  PrintPath("FOO_TEST_FILE_FOO :" "${FOO_TEST_FILE_FOO}")
+  PrintPath("FOO_TEST_FILE_ZOT :" "${FOO_TEST_FILE_ZOT}")
+  PrintPath("FOO_TEST_PATH_FOO :" "${FOO_TEST_PATH_FOO}")
+  PrintPath("FOO_TEST_PATH_ZOT :" "${FOO_TEST_PATH_ZOT}")
+  PrintPath("FOO_TEST_PROG_FOO :" "${FOO_TEST_PROG_FOO}")
+  CleanUpPackageRootTest()
+  message("")
+endmacro()
+
+set(Foo_ROOT      ${PackageRoot_BASE}/foo/cmake_root)
+set(ENV{Foo_ROOT} ${PackageRoot_BASE}/foo/env_root)
+RunPackageRootTest()
+message("----------")

+ 1 - 1
Tests/RunCMake/find_package/PackageRoot.cmake

@@ -1,5 +1,5 @@
-set(__UNDOCUMENTED_CMAKE_FIND_PACKAGE_ROOT 1)
 cmake_policy(SET CMP0057 NEW)
+cmake_policy(SET CMP0074 NEW)
 list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/PackageRoot)
 set(PackageRoot_BASE ${CMAKE_CURRENT_SOURCE_DIR}/PackageRoot)
 

+ 1 - 1
Tests/RunCMake/find_package/PackageRootNestedConfig.cmake

@@ -1,5 +1,5 @@
-set(__UNDOCUMENTED_CMAKE_FIND_PACKAGE_ROOT 1)
 cmake_policy(SET CMP0057 NEW)
+cmake_policy(SET CMP0074 NEW)
 list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/PackageRoot)
 set(PackageRoot_BASE ${CMAKE_CURRENT_SOURCE_DIR}/PackageRoot)
 

+ 1 - 1
Tests/RunCMake/find_package/PackageRootNestedModule.cmake

@@ -1,5 +1,5 @@
-set(__UNDOCUMENTED_CMAKE_FIND_PACKAGE_ROOT 1)
 cmake_policy(SET CMP0057 NEW)
+cmake_policy(SET CMP0074 NEW)
 list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/PackageRoot)
 set(PackageRoot_BASE ${CMAKE_CURRENT_SOURCE_DIR}/PackageRoot)
 

+ 2 - 0
Tests/RunCMake/find_package/RunCMakeTest.cmake

@@ -1,5 +1,7 @@
 include(RunCMake)
 
+run_cmake(CMP0074-WARN)
+run_cmake(CMP0074-OLD)
 run_cmake(ComponentRequiredAndOptional)
 run_cmake(MissingNormal)
 run_cmake(MissingNormalRequired)