Ver Fonte

ENH: Major improvements to the FIND_PACKAGE command. See bug #3659.

  - Use CMAKE_PREFIX_PATH and CMAKE_SYSTEM_PREFIX_PATH among other means
    to locate package configuration files.
  - Create cmFindCommon as base for cmFindBase and cmFindPackageCommand
  - Move common functionality up to cmFindCommon
  - Improve documentation of FIND_* commands.
  - Fix FIND_* commands to not add framework/app paths in wrong place.
Brad King há 18 anos atrás
pai
commit
b424df917d

+ 1 - 0
Source/cmBootstrapCommands.cxx

@@ -42,6 +42,7 @@
 #include "cmExecProgramCommand.cxx"
 #include "cmExternalMakefileProjectGenerator.cxx"
 #include "cmFindBase.cxx"
+#include "cmFindCommon.cxx"
 #include "cmFileCommand.cxx"
 #include "cmFindFileCommand.cxx"
 #include "cmFindLibraryCommand.cxx"

+ 42 - 344
Source/cmFindBase.cxx

@@ -18,26 +18,10 @@
   
 cmFindBase::cmFindBase()
 {
+  cmSystemTools::ReplaceString(this->GenericDocumentationPathsOrder,
+                               "FIND_ARGS_XXX", "<VAR> NAMES name");
   this->AlreadyInCache = false;
   this->AlreadyInCacheWithoutMetaInfo = false;
-  this->NoDefaultPath = false;
-  this->NoCMakePath = false;
-  this->NoCMakeEnvironmentPath = false;
-  this->NoSystemEnvironmentPath = false;
-  this->NoCMakeSystemPath = false;
-  this->FindRootPathMode = RootPathModeBoth;
-  // default is to search frameworks first on apple
-#if defined(__APPLE__)
-  this->SearchFrameworkFirst = true;
-  this->SearchAppBundleFirst = true;
-#else
-  this->SearchFrameworkFirst = false;
-  this->SearchAppBundleFirst = false;
-#endif
-  this->SearchFrameworkOnly = false;
-  this->SearchFrameworkLast = false;
-  this->SearchAppBundleOnly = false;
-  this->SearchAppBundleLast = false;
   this->GenericDocumentation = 
     "   FIND_XXX(<VAR> name1 path1 path2 ...)\n"
     "This is the short-hand signature for the command that "
@@ -54,8 +38,9 @@ cmFindBase::cmFindBase()
     "             [NO_CMAKE_PATH]\n"
     "             [NO_SYSTEM_ENVIRONMENT_PATH]\n"
     "             [NO_CMAKE_SYSTEM_PATH]\n"
-    "             [CMAKE_FIND_ROOT_PATH_BOTH | ONLY_CMAKE_FIND_ROOT_PATH | "
-                                               "NO_CMAKE_FIND_ROOT_PATH ]\n"
+    "             [CMAKE_FIND_ROOT_PATH_BOTH |\n"
+    "              ONLY_CMAKE_FIND_ROOT_PATH |\n"
+    "              NO_CMAKE_FIND_ROOT_PATH]\n"
     "            )\n"
     ""
     "This command is used to find a SEARCH_XXX_DESC. "
@@ -84,9 +69,8 @@ cmFindBase::cmFindBase()
     "can be skipped if NO_CMAKE_ENVIRONMENT_PATH is passed.\n"
     ""
     "   <prefix>/XXX_SUBDIR for each <prefix> in CMAKE_PREFIX_PATH\n"
-    "   CMAKE_FRAMEWORK_PATH\n"
-    "   CMAKE_APPBUNDLE_PATH\n"
     "   CMAKE_XXX_PATH\n"
+    "   CMAKE_XXX_MAC_PATH\n"
     "2. Search cmake variables with the same names as "
     "the cmake specific environment variables.  These "
     "are intended to be used on the command line with a "
@@ -94,9 +78,8 @@ cmFindBase::cmFindBase()
     "is passed.\n"
     ""
     "   <prefix>/XXX_SUBDIR for each <prefix> in CMAKE_PREFIX_PATH\n"
-    "   CMAKE_FRAMEWORK_PATH\n"
-    "   CMAKE_APPBUNDLE_PATH\n"
     "   CMAKE_XXX_PATH\n"
+    "   CMAKE_XXX_MAC_PATH\n"
     "3. Search the standard system environment variables. "
     "This can be skipped if NO_SYSTEM_ENVIRONMENT_PATH is an argument.\n"
     "   PATH\n"
@@ -105,51 +88,14 @@ cmFindBase::cmFindBase()
     "for the current system.  This can be skipped if NO_CMAKE_SYSTEM_PATH "
     "is passed.\n"
     "   <prefix>/XXX_SUBDIR for each <prefix> in CMAKE_SYSTEM_PREFIX_PATH\n"
-    "   CMAKE_SYSTEM_FRAMEWORK_PATH\n"
-    "   CMAKE_SYSTEM_APPBUNDLE_PATH\n"
     "   CMAKE_SYSTEM_XXX_PATH\n"
+    "   CMAKE_SYSTEM_XXX_MAC_PATH\n"
     "5. Search the paths specified after PATHS or in the short-hand version "
     "of the command.\n"
-    "On Darwin or systems supporting OSX Frameworks, the cmake variable"
-    "    CMAKE_FIND_FRAMEWORK can be set to empty or one of the following:\n"
-    "   \"FIRST\"  - Try to find frameworks before standard\n"
-    "              libraries or headers. This is the default on Darwin.\n"
-    "   \"LAST\"   - Try to find frameworks after standard\n"
-    "              libraries or headers.\n"
-    "   \"ONLY\"   - Only try to find frameworks.\n"
-    "   \"NEVER\". - Never try to find frameworks.\n"
-    "On Darwin or systems supporting OSX Application Bundles, the cmake "
-    "variable CMAKE_FIND_APPBUNDLE can be set to empty or one of the "
-    "following:\n"
-    "   \"FIRST\"  - Try to find application bundles before standard\n"
-    "              programs. This is the default on Darwin.\n"
-    "   \"LAST\"   - Try to find application bundles after standard\n"
-    "              programs.\n"
-    "   \"ONLY\"   - Only try to find application bundles.\n"
-    "   \"NEVER\". - Never try to find application bundles.\n"
-    "The CMake variable CMAKE_FIND_ROOT_PATH specifies one or more "
-    "directories to be prepended to all other search directories. "
-    "This effectively \"re-roots\" the entire search under given locations. "
-    "By default it is empty. It is especially useful when "
-    "cross-compiling to point to the root directory of the "
-    "target environment and CMake will search there too. By default at first "
-    "the directories listed in CMAKE_FIND_ROOT_PATH and then the non-rooted "
-    "directories will be searched. "
-    "The default behavior can be adjusted by setting "
-    "CMAKE_FIND_ROOT_PATH_MODE_XXX.  This behavior can be manually "
-    "overridden on a per-call basis. "
-    "By using CMAKE_FIND_ROOT_PATH_BOTH the search order will "
-    "be as described above. If NO_CMAKE_FIND_ROOT_PATH is used "
-    "then CMAKE_FIND_ROOT_PATH will not be used. If ONLY_CMAKE_FIND_ROOT_PATH "
-    "is used then only the re-rooted directories will be searched.\n"
-    "The reason the paths listed in the call to the command are searched "
-    "last is that most users of CMake would expect things to be found "
-    "first in the locations specified by their environment. Projects may "
-    "override this behavior by simply calling the command twice:\n"
-    "   FIND_XXX(<VAR> NAMES name PATHS paths NO_DEFAULT_PATH)\n"
-    "   FIND_XXX(<VAR> NAMES name)\n"
-    "Once one of these calls succeeds the result variable will be set "
-    "and stored in the cache so that neither call will search again.";
+    ;
+  this->GenericDocumentation += this->GenericDocumentationMacPolicy;
+  this->GenericDocumentation += this->GenericDocumentationRootPath;
+  this->GenericDocumentation += this->GenericDocumentationPathsOrder;
 }
   
 bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
@@ -159,57 +105,6 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
     this->SetError("called with incorrect number of arguments");
     return false;
     }
-  std::string ff = this->Makefile->GetSafeDefinition("CMAKE_FIND_FRAMEWORK");
-  if(ff == "NEVER")
-    {
-    this->SearchFrameworkLast = false;
-    this->SearchFrameworkFirst = false;
-    this->SearchFrameworkOnly = false;
-    }
-  else if (ff == "ONLY")
-    {
-    this->SearchFrameworkLast = false;
-    this->SearchFrameworkFirst = false;
-    this->SearchFrameworkOnly = true;
-    }
-  else if (ff == "FIRST")
-    {
-    this->SearchFrameworkLast = false;
-    this->SearchFrameworkFirst = true;
-    this->SearchFrameworkOnly = false;
-    }
-  else if (ff == "LAST")
-    {
-    this->SearchFrameworkLast = true;
-    this->SearchFrameworkFirst = false;
-    this->SearchFrameworkOnly = false;
-    }
-
-  std::string fab = this->Makefile->GetSafeDefinition("CMAKE_FIND_APPBUNDLE");
-  if(fab == "NEVER")
-    {
-    this->SearchAppBundleLast = false;
-    this->SearchAppBundleFirst = false;
-    this->SearchAppBundleOnly = false;
-    }
-  else if (fab == "ONLY")
-    {
-    this->SearchAppBundleLast = false;
-    this->SearchAppBundleFirst = false;
-    this->SearchAppBundleOnly = true;
-    }
-  else if (fab == "FIRST")
-    {
-    this->SearchAppBundleLast = false;
-    this->SearchAppBundleFirst = true;
-    this->SearchAppBundleOnly = false;
-    }
-  else if (fab == "LAST")
-    {
-    this->SearchAppBundleLast = true;
-    this->SearchAppBundleFirst = false;
-    this->SearchAppBundleOnly = false;
-    }
 
   // CMake versions below 2.3 did not search all these extra
   // locations.  Preserve compatibility unless a modern argument is
@@ -271,23 +166,12 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
     return true;
     }
   this->AlreadyInCache = false; 
-  
-  std::string findRootPathVar = "CMAKE_FIND_ROOT_PATH_MODE_";
-  findRootPathVar += this->CMakePathName;
-  std::string rootPathMode = 
-              this->Makefile->GetSafeDefinition(findRootPathVar.c_str());
-  if (rootPathMode=="NEVER")
-    {
-    this->FindRootPathMode = RootPathModeNoRootPath;
-    }
-  else if (rootPathMode=="ONLY")
-    {
-    this->FindRootPathMode = RootPathModeOnlyRootPath;
-    }
-  else if (rootPathMode=="BOTH")
-    {
-    this->FindRootPathMode = RootPathModeBoth;
-    }
+
+  // Find the current root path mode.
+  this->SelectDefaultRootPathMode();
+
+  // Find the current bundle/framework search policy.
+  this->SelectDefaultMacMode();
 
   std::vector<std::string> userPaths;
   std::string doc;
@@ -327,60 +211,12 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
       doingNames = false;
       this->NoDefaultPath = true;
       }
-    else if (args[j] == "NO_DEFAULT_PATH")
-      {
-      compatibility = false;
-      doingPaths = false;
-      doingPathSuf = false;
-      doingNames = false;
-      this->NoDefaultPath = true;
-      }
-    else if (args[j] == "NO_CMAKE_ENVIRONMENT_PATH")
-      {
-      compatibility = false;
-      doingPaths = false;
-      doingPathSuf = false;
-      doingNames = false;
-      this->NoCMakeEnvironmentPath = true;
-      }
-    else if (args[j] == "NO_CMAKE_PATH")
-      {
-      compatibility = false;
-      doingPaths = false;
-      doingPathSuf = false;
-      doingNames = false;
-      this->NoCMakePath = true;
-      }
-    else if (args[j] == "NO_SYSTEM_ENVIRONMENT_PATH")
-      {
-      compatibility = false;
-      doingPaths = false;
-      doingPathSuf = false;
-      doingNames = false;
-      this->NoSystemEnvironmentPath = true;
-      }
-    else if (args[j] == "NO_CMAKE_SYSTEM_PATH")
+    else if (this->CheckCommonArgument(args[j]))
       {
       compatibility = false;
       doingPaths = false;
       doingPathSuf = false;
       doingNames = false;
-      this->NoCMakeSystemPath = true;
-      }
-    else if (args[j] == "NO_CMAKE_FIND_ROOT_PATH")
-      {
-      compatibility = false;
-      this->FindRootPathMode = RootPathModeNoRootPath;
-      }
-    else if (args[j] == "ONLY_CMAKE_FIND_ROOT_PATH")
-      {
-      compatibility = false;
-      this->FindRootPathMode = RootPathModeOnlyRootPath;
-      }
-    else if (args[j] == "CMAKE_FIND_ROOT_PATH_BOTH")
-      {
-      compatibility = false;
-      this->FindRootPathMode = RootPathModeBoth;
       }
     else
       {
@@ -393,8 +229,8 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
         userPaths.push_back(args[j]);
         }
       else if(doingPathSuf)
-        { 
-        this->SearchPathSuffixes.push_back(args[j]);
+        {
+        this->AddPathSuffix(args[j]);
         }
       }
     }
@@ -446,8 +282,9 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
       }
     }
   this->ExpandPaths(userPaths);
-  
-  this->HandleCMakeFindRootPath();
+
+  // Handle search root stuff.
+  this->RerootPaths(this->SearchPaths);
   return true;
 }
 
@@ -457,11 +294,11 @@ void cmFindBase::ExpandPaths(std::vector<std::string> userPaths)
   // standard search paths.
   if(!this->NoDefaultPath)
     {
-    if(this->SearchFrameworkFirst)
+    if(this->SearchFrameworkFirst || this->SearchFrameworkOnly)
       {
       this->AddFrameWorkPaths();
       }
-    if(this->SearchAppBundleFirst)
+    if(this->SearchAppBundleFirst || this->SearchAppBundleOnly)
       {
       this->AddAppBundlePaths();
       }
@@ -509,55 +346,7 @@ void cmFindBase::ExpandPaths(std::vector<std::string> userPaths)
   this->AddPaths(paths);
 }
 
-void cmFindBase::HandleCMakeFindRootPath()
-{
-  if (this->FindRootPathMode == RootPathModeNoRootPath)
-    {
-    return;
-    }
-
-  const char* rootPath = this->Makefile->GetDefinition("CMAKE_FIND_ROOT_PATH");
-  if ((rootPath == 0) || (strlen(rootPath) == 0))
-    {
-    return;
-    }
-
-  std::vector<std::string> roots;
-  cmSystemTools::ExpandListArgument(rootPath, roots);
-
-  std::vector<std::string> unrootedPaths=this->SearchPaths;
-  this->SearchPaths.clear();
-
-  for (std::vector<std::string>::const_iterator rootIt = roots.begin();
-       rootIt != roots.end();
-       ++rootIt )
-    {
-    for (std::vector<std::string>::const_iterator it = unrootedPaths.begin();
-       it != unrootedPaths.end();
-       ++it )
-      {
-      // if the current directory is already inside the current root, don't
-      // add the root again
-      std::string rootedDir;
-      if (cmSystemTools::IsSubDirectory(it->c_str(), rootIt->c_str()))
-        {
-        rootedDir = *it;
-        }
-      else
-        {
-        rootedDir=*rootIt;
-        rootedDir+=*it;
-        }
-      this->SearchPaths.push_back(rootedDir);
-      }
-    }
-
-  if (this->FindRootPathMode == RootPathModeBoth)
-    {
-    this->AddPaths(unrootedPaths);
-    }
-}
-
+//----------------------------------------------------------------------------
 void cmFindBase::AddEnvironmentVariables()
 { 
   std::vector<std::string> paths;
@@ -570,14 +359,6 @@ void cmFindBase::AddEnvironmentVariables()
   var += this->CMakePathName;
   var += "_PATH";
   cmSystemTools::GetPath(paths, var.c_str());
-  if(this->SearchAppBundleLast)
-    {
-    cmSystemTools::GetPath(paths, "CMAKE_APPBUNDLE_PATH");
-    }
-  if(this->SearchFrameworkLast)
-    {
-    cmSystemTools::GetPath(paths, "CMAKE_FRAMEWORK_PATH");
-    }
   this->AddPaths(paths);
 }
 
@@ -585,15 +366,15 @@ void cmFindBase::AddFindPrefix(std::vector<std::string>& dest,
                                const std::vector<std::string>& src)
 {
   // default for programs
-  std::string subdir = "/bin";
+  std::string subdir = "bin";
 
   if (this->CMakePathName == "INCLUDE")
     {
-    subdir = "/include";
+    subdir = "include";
     }
   else if (this->CMakePathName == "LIBRARY")
     {
-    subdir = "/lib";
+    subdir = "lib";
     }
   else if (this->CMakePathName == "FRAMEWORK")
     {
@@ -604,14 +385,15 @@ void cmFindBase::AddFindPrefix(std::vector<std::string>& dest,
        it != src.end();
        ++it)
     {
-    std::string dirWithSubdir = it->c_str();
-    dirWithSubdir += subdir;
-    dest.push_back(dirWithSubdir);
-    if (subdir == "/bin")
+    std::string dir = it->c_str();
+    if(!subdir.empty() && !dir.empty() && dir[dir.size()-1] != '/')
+      {
+      dir += "/";
+      }
+    dest.push_back(dir + subdir);
+    if (subdir == "bin")
       {
-      dirWithSubdir = it->c_str();
-      dirWithSubdir += "/sbin";
-      dest.push_back(dirWithSubdir);
+      dest.push_back(dir + "sbin");
       }
     if(!subdir.empty())
       {
@@ -622,35 +404,9 @@ void cmFindBase::AddFindPrefix(std::vector<std::string>& dest,
 
 void cmFindBase::AddFrameWorkPaths()
 {
-  if(this->NoDefaultPath)
-    {
-    return;
-    }
   std::vector<std::string> paths;
-  // first environment variables
-  if(!this->NoCMakeEnvironmentPath)
-    {
-    cmSystemTools::GetPath(paths, "CMAKE_FRAMEWORK_PATH");
-    }
-  // add cmake variables
-  if(!this->NoCMakePath)
-    {
-    if(const char* path = 
-       this->Makefile->GetDefinition("CMAKE_FRAMEWORK_PATH"))
-      {
-      cmSystemTools::ExpandListArgument(path, paths);
-      }
-    }
-  // AddCMakeSystemVariables
-   if(!this->NoCMakeSystemPath)
-     {
-     if(const char* path = 
-        this->Makefile->GetDefinition("CMAKE_SYSTEM_FRAMEWORK_PATH"))
-       {
-       cmSystemTools::ExpandListArgument(path, paths);
-       }
-     }
-   this->AddPaths(paths);
+  this->GetFrameworkPaths(paths);
+  this->AddPaths(paths);
 }
 
 void cmFindBase::AddPaths(std::vector<std::string> & paths)
@@ -665,35 +421,9 @@ void cmFindBase::AddPaths(std::vector<std::string> & paths)
 
 void cmFindBase::AddAppBundlePaths()
 {
-  if(this->NoDefaultPath)
-    {
-    return;
-    }
   std::vector<std::string> paths;
-  // first environment variables
-  if(!this->NoCMakeEnvironmentPath)
-    {
-    cmSystemTools::GetPath(paths, "CMAKE_APPBUNDLE_PATH");
-    }
-  // add cmake variables
-  if(!this->NoCMakePath)
-    {
-    if(const char* path = 
-       this->Makefile->GetDefinition("CMAKE_APPBUNDLE_PATH"))
-      {
-      cmSystemTools::ExpandListArgument(path, paths);
-      }
-    }
-  // AddCMakeSystemVariables
-   if(!this->NoCMakeSystemPath)
-     {
-     if(const char* path = 
-        this->Makefile->GetDefinition("CMAKE_SYSTEM_APPBUNDLE_PATH"))
-       {
-       cmSystemTools::ExpandListArgument(path, paths);
-       }
-     }
-   this->AddPaths(paths);
+  this->GetAppBundlePaths(paths);
+  this->AddPaths(paths);
 }
 
 void cmFindBase::AddCMakeVariables()
@@ -715,22 +445,6 @@ void cmFindBase::AddCMakeVariables()
     {
     cmSystemTools::ExpandListArgument(path, paths);
     } 
-  if(this->SearchAppBundleLast)
-    {
-    if(const char* path = 
-       this->Makefile->GetDefinition("CMAKE_APPBUNDLE_PATH"))
-      {
-      cmSystemTools::ExpandListArgument(path, paths);
-      }
-    }
-  if(this->SearchFrameworkLast)
-    {
-    if(const char* path = 
-       this->Makefile->GetDefinition("CMAKE_FRAMEWORK_PATH"))
-      {
-      cmSystemTools::ExpandListArgument(path, paths);
-      }
-    }
   this->AddPaths(paths);
 }
 
@@ -764,22 +478,6 @@ void cmFindBase::AddCMakeSystemVariables()
     {
     cmSystemTools::ExpandListArgument(path, paths);
     }  
-  if(this->SearchAppBundleLast)
-    {
-    if(const char* path = 
-       this->Makefile->GetDefinition("CMAKE_SYSTEM_APPBUNDLE_PATH"))
-      {
-      cmSystemTools::ExpandListArgument(path, paths);
-      }
-    }
-  if(this->SearchFrameworkLast)
-    {
-    if(const char* path = 
-       this->Makefile->GetDefinition("CMAKE_SYSTEM_FRAMEWORK_PATH"))
-      {
-      cmSystemTools::ExpandListArgument(path, paths);
-      }
-    }
   this->AddPaths(paths);
 }
 

+ 6 - 28
Source/cmFindBase.h

@@ -17,15 +17,15 @@
 #ifndef cmFindBase_h
 #define cmFindBase_h
 
-#include "cmCommand.h"
+#include "cmFindCommon.h"
 
 /** \class cmFindBase
- * \brief Define a command to search for an executable program.
+ * \brief Base class for most FIND_XXX commands.
  *
  * cmFindBase is a parent class for cmFindProgramCommand, cmFindPathCommand,
- * and cmFindLibraryCommand, cmFindFile
+ * and cmFindLibraryCommand, cmFindFileCommand
  */
-class cmFindBase : public cmCommand
+class cmFindBase : public cmFindCommon
 {
 public:
   cmFindBase();
@@ -34,20 +34,15 @@ public:
    * the CMakeLists.txt file.
    */
   virtual bool ParseArguments(std::vector<std::string> const& args);
-  cmTypeMacro(cmFindBase, cmCommand);
+  cmTypeMacro(cmFindBase, cmFindCommon);
   
   virtual const char* GetFullDocumentation()
     {return this->GenericDocumentation.c_str();}
 
-  enum RootPathMode { RootPathModeBoth, 
-                      RootPathModeOnlyRootPath, 
-                      RootPathModeNoRootPath };
-  
 protected:
   void PrintFindStuff();
   void ExpandPaths(std::vector<std::string> userPaths);
-  void HandleCMakeFindRootPath();
-  
+
   // add to the SearchPaths
   void AddPaths(std::vector<std::string>& paths);
   void AddFrameWorkPaths();
@@ -70,29 +65,12 @@ protected:
   cmStdString VariableName;
   std::vector<std::string> Names;
   std::vector<std::string> SearchPaths;
-  std::vector<std::string> SearchPathSuffixes;
 
   // CMAKE_*_PATH CMAKE_SYSTEM_*_PATH FRAMEWORK|LIBRARY|INCLUDE|PROGRAM
-  cmStdString CMakePathName; 
   cmStdString EnvironmentPath; // LIB,INCLUDE
 
   bool AlreadyInCache;
   bool AlreadyInCacheWithoutMetaInfo;
-  bool NoDefaultPath;
-  bool NoCMakePath;
-  bool NoCMakeEnvironmentPath;
-  bool NoSystemEnvironmentPath;
-  bool NoCMakeSystemPath;
-  RootPathMode FindRootPathMode;
-  
-  bool SearchFrameworkFirst;
-  bool SearchFrameworkOnly;
-  bool SearchFrameworkLast;
-  
-  bool SearchAppBundleFirst;
-  bool SearchAppBundleOnly;
-  bool SearchAppBundleLast;
-  
 };
 
 

+ 479 - 0
Source/cmFindCommon.cxx

@@ -0,0 +1,479 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#include "cmFindCommon.h"
+
+//----------------------------------------------------------------------------
+cmFindCommon::cmFindCommon()
+{
+  this->FindRootPathMode = RootPathModeBoth;
+  this->NoDefaultPath = false;
+  this->NoCMakePath = false;
+  this->NoCMakeEnvironmentPath = false;
+  this->NoSystemEnvironmentPath = false;
+  this->NoCMakeSystemPath = false;
+
+  // OS X Bundle and Framework search policy.  The default is to
+  // search frameworks first on apple.
+#if defined(__APPLE__)
+  this->SearchFrameworkFirst = true;
+  this->SearchAppBundleFirst = true;
+#else
+  this->SearchFrameworkFirst = false;
+  this->SearchAppBundleFirst = false;
+#endif
+  this->SearchFrameworkOnly = false;
+  this->SearchFrameworkLast = false;
+  this->SearchAppBundleOnly = false;
+  this->SearchAppBundleLast = false;
+
+  // Documentation components.
+  this->GenericDocumentationMacPolicy =
+    "On Darwin or systems supporting OS X Frameworks, the cmake variable"
+    "    CMAKE_FIND_FRAMEWORK can be set to empty or one of the following:\n"
+    "   \"FIRST\"  - Try to find frameworks before standard\n"
+    "              libraries or headers. This is the default on Darwin.\n"
+    "   \"LAST\"   - Try to find frameworks after standard\n"
+    "              libraries or headers.\n"
+    "   \"ONLY\"   - Only try to find frameworks.\n"
+    "   \"NEVER\". - Never try to find frameworks.\n"
+    "On Darwin or systems supporting OS X Application Bundles, the cmake "
+    "variable CMAKE_FIND_APPBUNDLE can be set to empty or one of the "
+    "following:\n"
+    "   \"FIRST\"  - Try to find application bundles before standard\n"
+    "              programs. This is the default on Darwin.\n"
+    "   \"LAST\"   - Try to find application bundles after standard\n"
+    "              programs.\n"
+    "   \"ONLY\"   - Only try to find application bundles.\n"
+    "   \"NEVER\". - Never try to find application bundles.\n";
+  this->GenericDocumentationRootPath =
+    "The CMake variable CMAKE_FIND_ROOT_PATH specifies one or more "
+    "directories to be prepended to all other search directories. "
+    "This effectively \"re-roots\" the entire search under given locations. "
+    "By default it is empty. It is especially useful when "
+    "cross-compiling to point to the root directory of the "
+    "target environment and CMake will search there too. By default at first "
+    "the directories listed in CMAKE_FIND_ROOT_PATH and then the non-rooted "
+    "directories will be searched. "
+    "The default behavior can be adjusted by setting "
+    "CMAKE_FIND_ROOT_PATH_MODE_XXX.  This behavior can be manually "
+    "overridden on a per-call basis. "
+    "By using CMAKE_FIND_ROOT_PATH_BOTH the search order will "
+    "be as described above. If NO_CMAKE_FIND_ROOT_PATH is used "
+    "then CMAKE_FIND_ROOT_PATH will not be used. If ONLY_CMAKE_FIND_ROOT_PATH "
+    "is used then only the re-rooted directories will be searched.\n";
+  this->GenericDocumentationPathsOrder =
+    "The reason the paths listed in the call to the command are searched "
+    "last is that most users of CMake would expect things to be found "
+    "first in the locations specified by their environment.  Projects may "
+    "override this behavior by simply calling the command twice:\n"
+    "   FIND_XXX(FIND_ARGS_XXX PATHS paths... NO_DEFAULT_PATH)\n"
+    "   FIND_XXX(FIND_ARGS_XXX)\n"
+    "Once one of these calls succeeds the result variable will be set "
+    "and stored in the cache so that neither call will search again.";
+}
+
+//----------------------------------------------------------------------------
+cmFindCommon::~cmFindCommon()
+{
+}
+
+//----------------------------------------------------------------------------
+void cmFindCommon::SelectDefaultRootPathMode()
+{
+  // Use both by default.
+  this->FindRootPathMode = RootPathModeBoth;
+
+  // Check the policy variable for this find command type.
+  std::string findRootPathVar = "CMAKE_FIND_ROOT_PATH_MODE_";
+  findRootPathVar += this->CMakePathName;
+  std::string rootPathMode =
+    this->Makefile->GetSafeDefinition(findRootPathVar.c_str());
+  if (rootPathMode=="NEVER")
+    {
+    this->FindRootPathMode = RootPathModeNoRootPath;
+    }
+  else if (rootPathMode=="ONLY")
+    {
+    this->FindRootPathMode = RootPathModeOnlyRootPath;
+    }
+  else if (rootPathMode=="BOTH")
+    {
+    this->FindRootPathMode = RootPathModeBoth;
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmFindCommon::SelectDefaultMacMode()
+{
+  std::string ff = this->Makefile->GetSafeDefinition("CMAKE_FIND_FRAMEWORK");
+  if(ff == "NEVER")
+    {
+    this->SearchFrameworkLast = false;
+    this->SearchFrameworkFirst = false;
+    this->SearchFrameworkOnly = false;
+    }
+  else if(ff == "ONLY")
+    {
+    this->SearchFrameworkLast = false;
+    this->SearchFrameworkFirst = false;
+    this->SearchFrameworkOnly = true;
+    }
+  else if(ff == "FIRST")
+    {
+    this->SearchFrameworkLast = false;
+    this->SearchFrameworkFirst = true;
+    this->SearchFrameworkOnly = false;
+    }
+  else if(ff == "LAST")
+    {
+    this->SearchFrameworkLast = true;
+    this->SearchFrameworkFirst = false;
+    this->SearchFrameworkOnly = false;
+    }
+
+  std::string fab = this->Makefile->GetSafeDefinition("CMAKE_FIND_APPBUNDLE");
+  if(fab == "NEVER")
+    {
+    this->SearchAppBundleLast = false;
+    this->SearchAppBundleFirst = false;
+    this->SearchAppBundleOnly = false;
+    }
+  else if(fab == "ONLY")
+    {
+    this->SearchAppBundleLast = false;
+    this->SearchAppBundleFirst = false;
+    this->SearchAppBundleOnly = true;
+    }
+  else if(fab == "FIRST")
+    {
+    this->SearchAppBundleLast = false;
+    this->SearchAppBundleFirst = true;
+    this->SearchAppBundleOnly = false;
+    }
+  else if(fab == "LAST")
+    {
+    this->SearchAppBundleLast = true;
+    this->SearchAppBundleFirst = false;
+    this->SearchAppBundleOnly = false;
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmFindCommon::RerootPaths(std::vector<std::string>& paths)
+{
+#if 0
+  for(std::vector<std::string>::const_iterator i = paths.begin();
+      i != paths.end(); ++i)
+    {
+    fprintf(stderr, "[%s]\n", i->c_str());
+    }
+#endif
+
+  // Short-circuit if there is nothing to do.
+  if(this->FindRootPathMode == RootPathModeNoRootPath)
+    {
+    return;
+    }
+  const char* rootPath =
+    this->Makefile->GetDefinition("CMAKE_FIND_ROOT_PATH");
+  if((rootPath == 0) || (strlen(rootPath) == 0))
+    {
+    return;
+    }
+
+  // Construct the list of path roots with no trailing slashes.
+  std::vector<std::string> roots;
+  cmSystemTools::ExpandListArgument(rootPath, roots);
+  for(std::vector<std::string>::iterator ri = roots.begin();
+      ri != roots.end(); ++ri)
+    {
+    cmSystemTools::ConvertToUnixSlashes(*ri);
+    }
+
+  // Copy the original set of unrooted paths.
+  std::vector<std::string> unrootedPaths = paths;
+  paths.clear();
+
+  for(std::vector<std::string>::const_iterator ri = roots.begin();
+      ri != roots.end(); ++ri)
+    {
+    for(std::vector<std::string>::const_iterator ui = unrootedPaths.begin();
+        ui != unrootedPaths.end(); ++ui)
+      {
+      // Place the unrooted path under the current root if it is not
+      // already inside.  Skip the unrooted path if it is relative to
+      // a user home directory or is empty.
+      std::string rootedDir;
+      if(cmSystemTools::IsSubDirectory(ui->c_str(), ri->c_str()))
+        {
+        rootedDir = *ui;
+        }
+      else if(!ui->empty() && (*ui)[0] != '~')
+        {
+        // Start with the new root.
+        rootedDir = *ri;
+        rootedDir += "/";
+
+        // Append the original path with its old root removed.
+        rootedDir += cmSystemTools::SplitPathRootComponent(ui->c_str());
+        }
+
+      // Store the new path.
+      paths.push_back(rootedDir);
+      }
+    }
+
+  // If searching both rooted and unrooted paths add the original
+  // paths again.
+  if(this->FindRootPathMode == RootPathModeBoth)
+    {
+    paths.insert(paths.end(), unrootedPaths.begin(), unrootedPaths.end());
+    }
+}
+
+//----------------------------------------------------------------------------
+bool cmFindCommon::CheckCommonArgument(std::string const& arg)
+{
+  if(arg == "NO_DEFAULT_PATH")
+    {
+    this->NoDefaultPath = true;
+    }
+  else if(arg == "NO_CMAKE_ENVIRONMENT_PATH")
+    {
+    this->NoCMakeEnvironmentPath = true;
+    }
+  else if(arg == "NO_CMAKE_PATH")
+    {
+    this->NoCMakePath = true;
+    }
+  else if(arg == "NO_SYSTEM_ENVIRONMENT_PATH")
+    {
+    this->NoSystemEnvironmentPath = true;
+    }
+  else if(arg == "NO_CMAKE_SYSTEM_PATH")
+    {
+    this->NoCMakeSystemPath = true;
+    }
+  else if(arg == "NO_CMAKE_FIND_ROOT_PATH")
+    {
+    this->FindRootPathMode = RootPathModeNoRootPath;
+    }
+  else if(arg == "ONLY_CMAKE_FIND_ROOT_PATH")
+    {
+    this->FindRootPathMode = RootPathModeOnlyRootPath;
+    }
+  else if(arg == "CMAKE_FIND_ROOT_PATH_BOTH")
+    {
+    this->FindRootPathMode = RootPathModeBoth;
+    }
+  else
+    {
+    // The argument is not one of the above.
+    return false;
+    }
+
+  // The argument is one of the above.
+  return true;
+}
+
+//----------------------------------------------------------------------------
+void cmFindCommon::AddPathSuffix(std::string const& arg)
+{
+  std::string suffix = arg;
+
+  // Strip leading and trailing slashes.
+  if(suffix.empty())
+    {
+    return;
+    }
+  if(suffix[0] == '/')
+    {
+    suffix = suffix.substr(1, suffix.npos);
+    }
+  if(suffix.empty())
+    {
+    return;
+    }
+  if(suffix[suffix.size()-1] == '/')
+    {
+    suffix = suffix.substr(0, suffix.size()-1);
+    }
+  if(suffix.empty())
+    {
+    return;
+    }
+
+  // Store the suffix.
+  this->SearchPathSuffixes.push_back(suffix);
+}
+
+//----------------------------------------------------------------------------
+void cmFindCommon::GetAppBundlePaths(std::vector<std::string>& paths)
+{
+  if(this->NoDefaultPath)
+    {
+    return;
+    }
+  std::vector<std::string> tmp;
+
+  // first environment variables
+  if(!this->NoCMakeEnvironmentPath)
+    {
+    cmSystemTools::GetPath(tmp, "CMAKE_APPBUNDLE_PATH");
+    this->AddPathsInternal(paths, tmp, EnvPath);
+    tmp.clear();
+    }
+
+  // add cmake variables
+  if(!this->NoCMakePath)
+    {
+    if(const char* path =
+       this->Makefile->GetDefinition("CMAKE_APPBUNDLE_PATH"))
+      {
+      cmSystemTools::ExpandListArgument(path, tmp);
+      this->AddPathsInternal(paths, tmp, CMakePath);
+      tmp.clear();
+      }
+    }
+
+  // add cmake system variables
+  if(!this->NoCMakeSystemPath)
+    {
+    if(const char* path =
+       this->Makefile->GetDefinition("CMAKE_SYSTEM_APPBUNDLE_PATH"))
+      {
+      cmSystemTools::ExpandListArgument(path, tmp);
+      this->AddPathsInternal(paths, tmp, CMakePath);
+      tmp.clear();
+      }
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmFindCommon::GetFrameworkPaths(std::vector<std::string>& paths)
+{
+  if(this->NoDefaultPath)
+    {
+    return;
+    }
+  std::vector<std::string> tmp;
+
+  // first environment variables
+  if(!this->NoCMakeEnvironmentPath)
+    {
+    cmSystemTools::GetPath(tmp, "CMAKE_FRAMEWORK_PATH");
+    this->AddPathsInternal(paths, tmp, EnvPath);
+    tmp.clear();
+    }
+
+  // add cmake variables
+  if(!this->NoCMakePath)
+    {
+    if(const char* path =
+       this->Makefile->GetDefinition("CMAKE_FRAMEWORK_PATH"))
+      {
+      cmSystemTools::ExpandListArgument(path, tmp);
+      this->AddPathsInternal(paths, tmp, CMakePath);
+      tmp.clear();
+      }
+    }
+
+  // add cmake system variables
+  if(!this->NoCMakeSystemPath)
+    {
+    if(const char* path =
+       this->Makefile->GetDefinition("CMAKE_SYSTEM_FRAMEWORK_PATH"))
+      {
+      cmSystemTools::ExpandListArgument(path, tmp);
+      this->AddPathsInternal(paths, tmp, CMakePath);
+      tmp.clear();
+      }
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmFindCommon::AddCMakePath(std::vector<std::string>& out_paths,
+                                const char* variable,
+                                std::set<cmStdString>* emmitted)
+{
+  // Get a path from a CMake variable.
+  if(const char* varPath = this->Makefile->GetDefinition(variable))
+    {
+    std::vector<std::string> tmp;
+    cmSystemTools::ExpandListArgument(varPath, tmp);
+
+    // Relative paths are interpreted with respect to the current
+    // source directory.
+    this->AddPathsInternal(out_paths, tmp, CMakePath, emmitted);
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmFindCommon::AddEnvPath(std::vector<std::string>& out_paths,
+                              const char* variable,
+                              std::set<cmStdString>* emmitted)
+{
+  // Get a path from the environment.
+  std::vector<std::string> tmp;
+  cmSystemTools::GetPath(tmp, variable);
+
+  // Relative paths are interpreted with respect to the current
+  // working directory.
+  this->AddPathsInternal(out_paths, tmp, EnvPath, emmitted);
+}
+
+//----------------------------------------------------------------------------
+void cmFindCommon::AddPathsInternal(std::vector<std::string>& out_paths,
+                                    std::vector<std::string> const& in_paths,
+                                    PathType pathType,
+                                    std::set<cmStdString>* emmitted)
+{
+  for(std::vector<std::string>::const_iterator i = in_paths.begin();
+      i != in_paths.end(); ++i)
+    {
+    this->AddPathInternal(out_paths, *i, pathType, emmitted);
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmFindCommon::AddPathInternal(std::vector<std::string>& out_paths,
+                                   std::string const& in_path,
+                                   PathType pathType,
+                                   std::set<cmStdString>* emmitted)
+{
+  if(in_path.empty())
+    {
+    return;
+    }
+
+  // Select the base path with which to interpret relative paths.
+  const char* relbase = 0;
+  if(pathType == CMakePath)
+    {
+    relbase = this->Makefile->GetCurrentDirectory();
+    }
+
+  // Convert to clean full path.
+  std::string fullPath =
+    cmSystemTools::CollapseFullPath(in_path.c_str(), relbase);
+
+  // Insert the path if has not already been emmitted.
+  if(!emmitted || emmitted->insert(fullPath).second)
+    {
+    out_paths.push_back(fullPath.c_str());
+    }
+}

+ 95 - 0
Source/cmFindCommon.h

@@ -0,0 +1,95 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef cmFindCommon_h
+#define cmFindCommon_h
+
+#include "cmCommand.h"
+
+/** \class cmFindCommon
+ * \brief Base class for FIND_XXX implementations.
+ *
+ * cmFindCommon is a parent class for cmFindBase,
+ * cmFindProgramCommand, cmFindPathCommand, cmFindLibraryCommand,
+ * cmFindFileCommand, and cmFindPackageCommand.
+ */
+class cmFindCommon : public cmCommand
+{
+public:
+  cmFindCommon();
+  ~cmFindCommon();
+  cmTypeMacro(cmFindCommon, cmCommand);
+
+protected:
+
+  enum RootPathMode { RootPathModeBoth,
+                      RootPathModeOnlyRootPath,
+                      RootPathModeNoRootPath };
+
+  enum PathType { FullPath, CMakePath, EnvPath };
+
+  /** Place a set of search paths under the search roots.  */
+  void RerootPaths(std::vector<std::string>& paths);
+
+  /** Compute the current default root path mode.  */
+  void SelectDefaultRootPathMode();
+
+  /** Compute the current default bundle/framework search policy.  */
+  void SelectDefaultMacMode();
+
+  cmStdString CMakePathName;
+  RootPathMode FindRootPathMode;
+
+  bool CheckCommonArgument(std::string const& arg);
+  void AddPathSuffix(std::string const& arg);
+  void GetAppBundlePaths(std::vector<std::string>& paths);
+  void GetFrameworkPaths(std::vector<std::string>& paths);
+
+  void AddCMakePath(std::vector<std::string>& out_paths,
+                    const char* variable, std::set<cmStdString>* emmitted = 0);
+  void AddEnvPath(std::vector<std::string>& out_paths,
+                  const char* variable, std::set<cmStdString>* emmitted = 0);
+  void AddPathsInternal(std::vector<std::string>& out_paths,
+                        std::vector<std::string> const& in_paths,
+                        PathType pathType,
+                        std::set<cmStdString>* emmitted = 0);
+  void AddPathInternal(std::vector<std::string>& out_paths,
+                       std::string const& in_path,
+                       PathType pathType,
+                       std::set<cmStdString>* emmitted = 0);
+
+  bool NoDefaultPath;
+  bool NoCMakePath;
+  bool NoCMakeEnvironmentPath;
+  bool NoSystemEnvironmentPath;
+  bool NoCMakeSystemPath;
+
+  std::vector<std::string> SearchPathSuffixes;
+
+  std::string GenericDocumentationMacPolicy;
+  std::string GenericDocumentationRootPath;
+  std::string GenericDocumentationPathsOrder;
+
+  bool SearchFrameworkFirst;
+  bool SearchFrameworkOnly;
+  bool SearchFrameworkLast;
+
+  bool SearchAppBundleFirst;
+  bool SearchAppBundleOnly;
+  bool SearchAppBundleLast;
+};
+
+#endif

+ 6 - 0
Source/cmFindLibraryCommand.cxx

@@ -23,6 +23,12 @@ cmFindLibraryCommand::cmFindLibraryCommand()
                                "FIND_XXX", "find_library");
   cmSystemTools::ReplaceString(this->GenericDocumentation,
                                "CMAKE_XXX_PATH", "CMAKE_LIBRARY_PATH");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "CMAKE_XXX_MAC_PATH",
+                               "CMAKE_FRAMEWORK_PATH");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "CMAKE_SYSTEM_XXX_MAC_PATH",
+                               "CMAKE_SYSTEM_FRAMEWORK_PATH");
   cmSystemTools::ReplaceString(this->GenericDocumentation,
                                "XXX_SYSTEM", "LIB");
   cmSystemTools::ReplaceString(this->GenericDocumentation,

+ 1174 - 180
Source/cmFindPackageCommand.cxx

@@ -47,6 +47,158 @@ void cmFindPackageNeedBackwardsCompatibility(const std::string& variable,
 #endif
 }
 
+//----------------------------------------------------------------------------
+cmFindPackageCommand::cmFindPackageCommand()
+{
+  cmSystemTools::ReplaceString(this->GenericDocumentationRootPath,
+                               "CMAKE_FIND_ROOT_PATH_MODE_XXX",
+                               "CMAKE_FIND_ROOT_PATH_MODE_PACKAGE");
+  cmSystemTools::ReplaceString(this->GenericDocumentationPathsOrder,
+                               "FIND_ARGS_XXX", "<package>");
+  cmSystemTools::ReplaceString(this->GenericDocumentationPathsOrder,
+                               "FIND_XXX", "find_package");
+  this->CMakePathName = "PACKAGE";
+  this->Quiet = false;
+  this->Required = false;
+  this->NoBuilds = false;
+  this->NoModule = false;
+  this->DebugMode = false;
+  this->CommandDocumentation =
+    "  find_package(<package> [major.minor] [QUIET] [NO_MODULE]\n"
+    "               [[REQUIRED|COMPONENTS] [components...]]\n"
+    "               [NAMES name1 [name2 ...]]\n"
+    "               [CONFIGS config1 [config2 ...]]\n"
+    "               [PATHS path1 [path2 ... ]]\n"
+    "               [PATH_SUFFIXES suffix1 [suffix2 ...]]\n"
+    "               [NO_DEFAULT_PATH]\n"
+    "               [NO_CMAKE_ENVIRONMENT_PATH]\n"
+    "               [NO_CMAKE_PATH]\n"
+    "               [NO_SYSTEM_ENVIRONMENT_PATH]\n"
+    "               [NO_CMAKE_BUILDS_PATH]\n"
+    "               [NO_CMAKE_SYSTEM_PATH]\n"
+    "               [CMAKE_FIND_ROOT_PATH_BOTH |\n"
+    "                ONLY_CMAKE_FIND_ROOT_PATH |\n"
+    "                NO_CMAKE_FIND_ROOT_PATH])\n"
+    "Finds and loads settings from an external project.  <package>_FOUND "
+    "will be set to indicate whether the package was found.  Settings that "
+    "can be used when <package>_FOUND is true are package-specific.  "
+    "A package-specific list of components may be listed after the "
+    "REQUIRED option, or after the COMPONENTS option if no REQUIRED "
+    "option is given.  The \"major.minor\" version argument is currently "
+    "a placeholder for future use and is ignored.  "
+    "The command has two modes by which it searches for packages: "
+    "\"Module\" mode and \"Config\" mode."
+    "\n"
+    "Module mode has a reduced signature:\n"
+    "  find_package(<package> [major.minor] [QUIET]\n"
+    "               [[REQUIRED|COMPONENTS] [components...]])\n"
+    "CMake searches for a file called \"Find<package>.cmake\" in "
+    "the CMAKE_MODULE_PATH followed by the CMake installation.  "
+    "If the file is found, it is read and processed by CMake.  "
+    "It is responsible for finding the package "
+    "or producing an error message if package content cannot be found.  "
+    "Otherwise the command proceeds to Config mode.  The NO_MODULE "
+    "option may be used to skip Module mode explicitly, but the option "
+    "is implied by use of options not specified in the reduced signature."
+    "\n"
+    "Config mode attempts to locate a configuration file provided by the "
+    "package to be found.  A cache entry called <package>_DIR is created to "
+    "hold the directory containing the file.  "
+    "By default the command searches for a package with the name <package>.  "
+    "If the NAMES option is given the names following it are used instead "
+    "of <package>.  "
+    "The command searches for a file called \"<name>Config.cmake\" or "
+    "\"<lower-case-name>-config.cmake\" for each name specified.  "
+    "A replacement set of possible configuration file names may be given "
+    "using the CONFIGS option.  "
+    "The search procedure is specified below.  Once found, the configuration "
+    "file is read and processed by CMake.  Since the file is provided by the "
+    "package it already knows the location of package contents.  "
+    "The full path to the configuration file is stored in the cmake "
+    "variable <package>_CONFIG."
+    "\n"
+    "If the package configuration file cannot be found CMake "
+    "will generate an error describing the problem unless the QUIET "
+    "argument is specified.  If REQUIRED is specified and the package "
+    "is not found a fatal error is generated and the configure step stops "
+    "executing.  If <package>_DIR has been set to a directory not containing "
+    "a configuration file a fatal error is always generated because user "
+    "intervention is required."
+    "\n"
+    "CMake constructs a set of possible installation prefixes for the "
+    "package.  Under each prefix the following directories are searched "
+    "for a configuration file:\n"
+    "  <prefix>/                                               (W)\n"
+    "  <prefix>/(cmake|CMake)/                                 (W)\n"
+    "  <prefix>/(share|lib)/<name>*/                           (P)\n"
+    "  <prefix>/(share|lib)/<name>*/(cmake|CMake)/             (P)\n"
+    "On systems supporting OS X Frameworks and Application Bundles "
+    "the following directories are searched for frameworks or bundles "
+    "containing a configuration file:\n"
+    "  <prefix>/<name>.framework/Resources/                    (A)\n"
+    "  <prefix>/<name>.framework/Resources/CMake/              (A)\n"
+    "  <prefix>/<name>.framework/Versions/*/Resources/         (A)\n"
+    "  <prefix>/<name>.framework/Versions/*/Resources/CMake/   (A)\n"
+    "  <prefix>/<name>.app/Contents/Resources/                 (A)\n"
+    "  <prefix>/<name>.app/Contents/Resources/CMake/           (A)\n"
+    "In all cases the <name> is treated as case-insensitive and corresponds "
+    "to any of the names specified (<package> or names given by NAMES).  "
+    "If PATH_SUFFIXES is specified the suffixes are appended to each "
+    "(W) or (P) directory entry one-by-one.\n"
+    "This set of directories is intended to work in cooperation with "
+    "projects that provide configuration files in their installation trees.  "
+    "Directories above marked with (W) are intended for installations on "
+    "Windows where the prefix may point at the top of an application's "
+    "installation directory.  Those marked with (P) are intended for "
+    "installations on POSIX platforms where the prefix is shared by "
+    "multiple packages.  This is merely a convention, so all (W) and (P) "
+    "directories are still searched on all platforms.  "
+    "Directories marked with (A) are intended for installations on "
+    "Apple platforms.  The cmake variables CMAKE_FIND_FRAMEWORK and "
+    "CMAKE_FIND_APPBUNDLE determine the order of preference "
+    "as specified below.\n"
+    "The set of installation prefixes is constructed using the following "
+    "steps.  If NO_DEFAULT_PATH is specified steps 1-5 are skipped.\n"
+    "1. Search cmake specific environment variables.  This "
+    "can be skipped if NO_CMAKE_ENVIRONMENT_PATH is passed.\n"
+    "   CMAKE_PREFIX_PATH\n"
+    "   CMAKE_FRAMEWORK_PATH\n"
+    "   CMAKE_APPBUNDLE_PATH\n"
+    "2. Search cmake variables with the same names as the cmake specific "
+    "environment variables.  These are intended to be used on the command "
+    "line with a -DVAR=value.  This can be skipped if NO_CMAKE_PATH "
+    "is passed.\n"
+    "   CMAKE_PREFIX_PATH\n"
+    "   CMAKE_FRAMEWORK_PATH\n"
+    "   CMAKE_APPBUNDLE_PATH\n"
+    "3. 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.\n"
+    "   PATH\n"
+    "4. Search project build trees recently configured in a CMake GUI.  "
+    "This can be skipped if NO_CMAKE_BUILDS_PATH is passed.  "
+    "It is intended for the case when a user is building multiple "
+    "dependent projects one after another.\n"
+    "5. Search cmake variables defined in the Platform files "
+    "for the current system.  This can be skipped if NO_CMAKE_SYSTEM_PATH "
+    "is passed.\n"
+    "   CMAKE_SYSTEM_PREFIX_PATH\n"
+    "   CMAKE_SYSTEM_FRAMEWORK_PATH\n"
+    "   CMAKE_SYSTEM_APPBUNDLE_PATH\n"
+    "6. Search paths specified by the PATHS option.\n"
+    ;
+  this->CommandDocumentation += this->GenericDocumentationMacPolicy;
+  this->CommandDocumentation += this->GenericDocumentationRootPath;
+  this->CommandDocumentation += this->GenericDocumentationPathsOrder;
+}
+
+//----------------------------------------------------------------------------
+const char* cmFindPackageCommand::GetFullDocumentation()
+{
+  return this->CommandDocumentation.c_str();
+}
+
 //----------------------------------------------------------------------------
 bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
 {
@@ -56,40 +208,94 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
     return false;
     }
 
+  // Check for debug mode.
+  this->DebugMode = this->Makefile->IsOn("CMAKE_FIND_DEBUG_MODE");
+
+  // Find the current root path mode.
+  this->SelectDefaultRootPathMode();
+
+  // Find the current bundle/framework search policy.
+  this->SelectDefaultMacMode();
+
   // Record options.
   this->Name = args[0];
-  bool quiet = false;
-  bool required = false;
-  bool no_module = false;
   std::string components;
   const char* components_sep = "";
 
+  // Check ancient compatibility.
+  this->Compatibility_1_6 =
+    this->Makefile->GetLocalGenerator()
+    ->NeedBackwardsCompatibility(1, 6);
+
+  // Always search directly in a generated path.
+  this->SearchPathSuffixes.push_back("");
+
   // Parse the arguments.
-  bool doing_components = false;
+  enum Doing { DoingNone, DoingComponents, DoingNames, DoingPaths,
+               DoingPathSuffixes, DoingConfigs };
+  Doing doing = DoingNone;
   cmsys::RegularExpression version("^[0-9.]+$");
   bool haveVersion = false;
   for(unsigned int i=1; i < args.size(); ++i)
     {
     if(args[i] == "QUIET")
       {
-      quiet = true;
-      doing_components = false;
+      this->Quiet = true;
+      doing = DoingNone;
       }
     else if(args[i] == "NO_MODULE")
       {
-      no_module = true;
-      doing_components = false;
+      this->NoModule = true;
+      doing = DoingNone;
       }
     else if(args[i] == "REQUIRED")
       {
-      required = true;
-      doing_components = true;
+      this->Required = true;
+      doing = DoingComponents;
       }
     else if(args[i] == "COMPONENTS")
       {
-      doing_components = true;
+      this->Compatibility_1_6 = false;
+      doing = DoingComponents;
+      }
+    else if(args[i] == "NAMES")
+      {
+      this->NoModule = true;
+      this->Compatibility_1_6 = false;
+      doing = DoingNames;
       }
-    else if(doing_components)
+    else if(args[i] == "PATHS")
+      {
+      this->NoModule = true;
+      this->Compatibility_1_6 = false;
+      doing = DoingPaths;
+      }
+    else if(args[i] == "PATH_SUFFIXES")
+      {
+      this->NoModule = true;
+      this->Compatibility_1_6 = false;
+      doing = DoingPathSuffixes;
+      }
+    else if(args[i] == "CONFIGS")
+      {
+      this->NoModule = true;
+      this->Compatibility_1_6 = false;
+      doing = DoingConfigs;
+      }
+    else if(args[i] == "NO_CMAKE_BUILDS_PATH")
+      {
+      this->NoBuilds = true;
+      this->NoModule = true;
+      this->Compatibility_1_6 = false;
+      doing = DoingNone;
+      }
+    else if(this->CheckCommonArgument(args[i]))
+      {
+      this->NoModule = true;
+      this->Compatibility_1_6 = false;
+      doing = DoingNone;
+      }
+    else if(doing == DoingComponents)
       {
       // Set a variable telling the find script this component
       // is required.
@@ -101,6 +307,22 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
       components += args[i];
       components_sep = ";";
       }
+    else if(doing == DoingNames)
+      {
+      this->Names.push_back(args[i]);
+      }
+    else if(doing == DoingPaths)
+      {
+      this->AddUserPath(args[i]);
+      }
+    else if(doing == DoingPathSuffixes)
+      {
+      this->AddPathSuffix(args[i]);
+      }
+    else if(doing == DoingConfigs)
+      {
+      this->Configs.push_back(args[i]);
+      }
     else if(!haveVersion && version.find(args[i].c_str()))
       {
       haveVersion = true;
@@ -118,48 +340,105 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
   std::string components_var = Name + "_FIND_COMPONENTS";
   this->Makefile->AddDefinition(components_var.c_str(), components.c_str());
 
-  // See if there is a Find<name>.cmake module.
-  if(!no_module)
+  // See if there is a Find<package>.cmake module.
+  if(!this->NoModule)
     {
     bool foundModule = false;
-    if(!this->FindModule(foundModule, quiet, required))
+    if(!this->FindModule(foundModule))
       {
-      this->AppendSuccessInformation(quiet);
+      this->AppendSuccessInformation();
       return false;
       }
     if(foundModule)
       {
-      this->AppendSuccessInformation(quiet);
+      this->AppendSuccessInformation();
       return true;
       }
     }
 
   // No find module.  Assume the project has a CMake config file.  Use
-  // a <NAME>_DIR cache variable to locate it.
+  // a <package>_DIR cache variable to locate it.
   this->Variable = this->Name;
   this->Variable += "_DIR";
-  this->Config = this->Name;
-  this->Config += "Config.cmake";
 
+  // Add the default name.
+  if(this->Names.empty())
+    {
+    this->Names.push_back(this->Name);
+    }
+
+  // Add the default configs.
+  if(this->Configs.empty())
+    {
+    for(std::vector<std::string>::const_iterator ni = this->Names.begin();
+        ni != this->Names.end(); ++ni)
+      {
+      std::string config = *ni;
+      config += "Config.cmake";
+      this->Configs.push_back(config);
+
+      config = cmSystemTools::LowerCase(*ni);
+      config += "-config.cmake";
+      this->Configs.push_back(config);
+      }
+    }
+
+  // Find and load the package.
+  bool result = this->HandlePackageMode();
+  this->AppendSuccessInformation();
+  return result;
+}
+
+//----------------------------------------------------------------------------
+bool cmFindPackageCommand::FindModule(bool& found)
+{
+  std::string module = "Find";
+  module += this->Name;
+  module += ".cmake";
+  std::string mfile = this->Makefile->GetModulesFile(module.c_str());
+  if ( mfile.size() )
+    {
+    if(this->Quiet)
+      {
+      // Tell the module that is about to be read that it should find
+      // quietly.
+      std::string quietly = this->Name;
+      quietly += "_FIND_QUIETLY";
+      this->Makefile->AddDefinition(quietly.c_str(), "1");
+      }
+
+    if(this->Required)
+      {
+      // Tell the module that is about to be read that it should report
+      // a fatal error if the package is not found.
+      std::string req = this->Name;
+      req += "_FIND_REQUIRED";
+      this->Makefile->AddDefinition(req.c_str(), "1");
+      }
+
+    // Load the module we found.
+    found = true;
+    return this->ReadListFile(mfile.c_str());
+    }
+  return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmFindPackageCommand::HandlePackageMode()
+{
   // Support old capitalization behavior.
   std::string upperDir = cmSystemTools::UpperCase(this->Name);
   std::string upperFound = cmSystemTools::UpperCase(this->Name);
   upperDir += "_DIR";
   upperFound += "_FOUND";
-  bool needCompatibility = false;
-  if(!(upperDir == this->Variable))
+  if(upperDir == this->Variable)
     {
-    const char* versionValue =
-      this->Makefile->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
-    if(atof(versionValue) < 1.7)
-      {
-      needCompatibility = true;
-      }
+    this->Compatibility_1_6 = false;
     }
 
   // Try to find the config file.
   const char* def = this->Makefile->GetDefinition(this->Variable.c_str());
-  if(needCompatibility && cmSystemTools::IsOff(def))
+  if(this->Compatibility_1_6 && cmSystemTools::IsOff(def))
     {
     // Use the setting of the old name of the variable to provide the
     // value of the new.
@@ -170,70 +449,104 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
       def = this->Makefile->GetDefinition(this->Variable.c_str());
       }
     }
+
+  // Search for the config file if it is not already found.
   if(cmSystemTools::IsOff(def))
     {
-    if(!this->FindConfig())
-      {
-      this->AppendSuccessInformation(quiet);
-      return false;
-      }
+    this->FindConfig();
+    def = this->Makefile->GetDefinition(this->Variable.c_str());
     }
 
   // If the config file was found, load it.
+  std::string file;
   bool result = true;
   bool found = false;
-  def = this->Makefile->GetDefinition(this->Variable.c_str());
   if(!cmSystemTools::IsOff(def))
     {
-    std::string f = def;
-    cmSystemTools::ConvertToUnixSlashes(f);
-    f += "/";
-    f += this->Config;
-    if(!cmSystemTools::FileIsFullPath(f.c_str()))
+    // Get the directory from the variable value.
+    std::string dir = def;
+    cmSystemTools::ConvertToUnixSlashes(dir);
+
+    // Treat relative paths with respect to the current source dir.
+    if(!cmSystemTools::FileIsFullPath(dir.c_str()))
       {
-      f = "/" + f;
-      f = this->Makefile->GetCurrentDirectory() + f;
+      dir = "/" + dir;
+      dir = this->Makefile->GetCurrentDirectory() + dir;
       }
 
-    if(cmSystemTools::FileExists(f.c_str()))
+    // Find the configuration file.
+    if(this->FindConfigFile(dir, file))
       {
-      if(this->ReadListFile(f.c_str()))
+      // Parse the configuration file.
+      if(this->ReadListFile(file.c_str()))
         {
+        // The package has been found.
         found = true;
         }
       else
         {
+        // The configuration file is invalid.
         result = false;
         }
       }
     else
       {
+      // The variable setting is wrong.
       cmOStringStream e;
-      e << this->Variable << " is set to \"" << def << "\", which is "
-        << "not a directory containing " << this->Config;
-      cmSystemTools::Error(e.str().c_str());
-      if(required)
-        {
-        cmSystemTools::SetFatalErrorOccured();
-        }
-      result = true;
+      e << "cannot find package " << this->Name << " because "
+        << this->Variable << " is set to \"" << def << "\" "
+        << "which is not a directory containing a package configuration "
+        << "file.  "
+        << "Please set the cache entry " << this->Variable << " "
+        << "to the correct directory, or delete it to ask CMake "
+        << "to search.";
+      this->SetError(e.str().c_str());
+      result = false;
       }
     }
-  else if(!quiet || required)
+  else if(!this->Quiet || this->Required)
     {
+    // The variable is not set.
     cmOStringStream e;
-    e << "FIND_PACKAGE could not find Find" << this->Name
-      << ".cmake nor config file " << this->Config << ".\n"
-      << "Adjust CMAKE_MODULE_PATH to find Find" << this->Name
-      << ".cmake or set " << this->Variable
-      << "\nto the directory containing " << this->Config
-      << " in order to use " << this->Name << ".";
-    cmSystemTools::Error(e.str().c_str());
-    if(required)
+    e << "could not find ";
+    if(!this->NoModule)
+      {
+      e << "module Find" << this->Name << ".cmake or ";
+      }
+    e << "a configuration file for package " << this->Name << ".\n";
+    if(!this->NoModule)
+      {
+      e << "Adjust CMAKE_MODULE_PATH to find Find"
+        << this->Name << ".cmake or set ";
+      }
+    else
+      {
+      e << "Set ";
+      }
+    e << this->Variable << " to the directory containing a CMake "
+      << "configuration file for " << this->Name << ".  ";
+    if(this->Configs.size() == 1)
+      {
+      e << "The file will be called " << this->Configs[0];
+      }
+    else
+      {
+      e << "The file will have one of the following names:\n";
+      for(std::vector<std::string>::const_iterator ci = this->Configs.begin();
+          ci != this->Configs.end(); ++ci)
+        {
+        e << "  " << *ci << "\n";
+        }
+      }
+    if(this->Required)
+      {
+      this->SetError(e.str().c_str());
+      result = false;
+      }
+    else
       {
-      cmSystemTools::SetFatalErrorOccured();
+      cmSystemTools::Error("find_package ", e.str().c_str());
       }
-    result = true;
     }
 
   // Set a variable marking whether the package was found.
@@ -241,7 +554,20 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
   foundVar += "_FOUND";
   this->Makefile->AddDefinition(foundVar.c_str(), found? "1":"0");
 
-  if(needCompatibility)
+  // Set a variable naming the configuration file that was found.
+  std::string fileVar = this->Name;
+  fileVar += "_CONFIG";
+  if(found)
+    {
+    this->Makefile->AddDefinition(fileVar.c_str(), file.c_str());
+    }
+  else
+    {
+    this->Makefile->RemoveDefinition(fileVar.c_str());
+    }
+
+  // Handle some ancient compatibility stuff.
+  if(this->Compatibility_1_6)
     {
     // Listfiles will be looking for the capitalized version of the
     // name.  Provide it.
@@ -256,7 +582,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
 #ifdef CMAKE_BUILD_WITH_CMAKE
   if(!(upperDir == this->Variable))
     {
-    if(needCompatibility)
+    if(this->Compatibility_1_6)
       {
       // Listfiles may use the capitalized version of the name.
       // Remove any previously added watch.
@@ -277,155 +603,107 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
     }
 #endif
 
-  this->AppendSuccessInformation(quiet);
   return result;
 }
 
 //----------------------------------------------------------------------------
-bool cmFindPackageCommand::FindModule(bool& found, bool quiet, bool required)
+void cmFindPackageCommand::FindConfig()
 {
-  std::string module = "Find";
-  module += this->Name;
-  module += ".cmake";
-  std::string mfile = this->Makefile->GetModulesFile(module.c_str());
-  if ( mfile.size() )
-    {
-    if(quiet)
-      {
-      // Tell the module that is about to be read that it should find
-      // quietly.
-      std::string quietly = this->Name;
-      quietly += "_FIND_QUIETLY";
-      this->Makefile->AddDefinition(quietly.c_str(), "1");
-      }
+  // Compute the set of search prefixes.
+  this->ComputePrefixes();
 
-    if(required)
-      {
-      // Tell the module that is about to be read that it should report
-      // a fatal error if the package is not found.
-      std::string req = this->Name;
-      req += "_FIND_REQUIRED";
-      this->Makefile->AddDefinition(req.c_str(), "1");
-      }
+  // Look for the project's configuration file.
+  bool found = false;
 
-    // Load the module we found.
-    found = true;
-    return this->ReadListFile(mfile.c_str());
+  // Search for frameworks.
+  if(!found && this->SearchFrameworkFirst || this->SearchFrameworkOnly)
+    {
+    found = this->FindFrameworkConfig();
     }
-  return true;
-}
 
-//----------------------------------------------------------------------------
-bool cmFindPackageCommand::FindConfig()
-{
-  std::string help = "The directory containing ";
-  help += this->Config;
-  help += ".";
-
-  // Construct the list of relative paths to each prefix to be
-  // searched.
-  std::string rel = "/lib/";
-  rel += cmSystemTools::LowerCase(this->Name);
-  this->Relatives.push_back(rel);
-  rel = "/lib/";
-  rel += this->Name;
-  this->Relatives.push_back(rel);
+  // Search for apps.
+  if(!found && this->SearchAppBundleFirst || this->SearchAppBundleOnly)
+    {
+    found = this->FindAppBundleConfig();
+    }
 
-  // It is likely that CMake will have recently built the project.
-  for(int i=1; i <= 10; ++i)
+  // Search prefixes.
+  if(!found && !(this->SearchFrameworkOnly || this->SearchAppBundleOnly))
     {
-    cmOStringStream r;
-    r << "[HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\"
-      "Settings\\StartPath;WhereBuild" << i << "]";
-    std::string entry = r.str();
-    cmSystemTools::ExpandRegistryValues(entry);
-    cmSystemTools::ConvertToUnixSlashes(entry);
-    if(cmSystemTools::FileIsDirectory(entry.c_str()))
-      {
-      this->Builds.push_back(entry);
-      }
+    found = this->FindPrefixedConfig();
     }
 
-  // The project may be installed.  Use the system search path to
-  // construct a list of possible install prefixes.
-  std::vector<std::string> systemPath;
-  cmSystemTools::GetPath(systemPath);
-  for(std::vector<std::string>::iterator i = systemPath.begin();
-      i != systemPath.end(); ++i)
+  // Search for frameworks.
+  if(!found && this->SearchFrameworkLast)
     {
-    *i += "/..";
-    if(cmSystemTools::FileIsDirectory(i->c_str()))
-      {
-      this->Prefixes.push_back(cmSystemTools::CollapseFullPath(i->c_str()));
-      }
+    found = this->FindFrameworkConfig();
     }
-#if !defined(WIN32) || defined(__CYGWIN__)
-  this->Prefixes.push_back("/usr/local");
-  this->Prefixes.push_back("/usr");
-#endif
 
-  // Look for the project's configuration file.
-  std::string init = this->SearchForConfig();
+  // Search for apps.
+  if(!found && this->SearchAppBundleLast)
+    {
+    found = this->FindAppBundleConfig();
+    }
 
   // Store the entry in the cache so it can be set by the user.
+  std::string init;
+  if(found)
+    {
+    init = cmSystemTools::GetFilenamePath(this->FileFound);
+    }
+  else
+    {
+    init = this->Variable + "-NOTFOUND";
+    }
+  std::string help =
+    "The directory containing a CMake configuration file for ";
+  help += this->Name;
+  help += ".";
   this->Makefile->AddCacheDefinition(this->Variable.c_str(),
-                                 init.c_str(),
-                                 help.c_str(),
-                                 cmCacheManager::PATH);
-  return true;
+                                     init.c_str(), help.c_str(),
+                                     cmCacheManager::PATH);
 }
 
 //----------------------------------------------------------------------------
-std::string cmFindPackageCommand::SearchForConfig() const
+bool cmFindPackageCommand::FindPrefixedConfig()
 {
-  // Check the environment variable.
-  std::string env;
-  if(cmSystemTools::GetEnv(this->Variable.c_str(), env) && env.length() > 0)
+  for(std::vector<std::string>::const_iterator pi = this->Prefixes.begin();
+      pi != this->Prefixes.end(); ++pi)
     {
-    cmSystemTools::ConvertToUnixSlashes(env);
-    std::string f = env;
-    f += "/";
-    f += this->Config;
-    if(cmSystemTools::FileExists(f.c_str()))
+    if(this->SearchPrefix(*pi))
       {
-      return env;
+      return true;
       }
     }
+  return false;
+}
 
-  // Search the build directories.
-  for(std::vector<cmStdString>::const_iterator b = this->Builds.begin();
-      b != this->Builds.end(); ++b)
+//----------------------------------------------------------------------------
+bool cmFindPackageCommand::FindFrameworkConfig()
+{
+  for(std::vector<std::string>::const_iterator i = this->Prefixes.begin();
+      i != this->Prefixes.end(); ++i)
     {
-    std::string f = *b;
-    f += "/";
-    f += this->Config;
-    if(cmSystemTools::FileExists(f.c_str()))
+    if(this->SearchFrameworkPrefix(*i))
       {
-      return *b;
+      return true;
       }
     }
+  return false;
+}
 
-  // Search paths relative to each installation prefix.
-  for(std::vector<cmStdString>::const_iterator p = this->Prefixes.begin();
-      p != this->Prefixes.end(); ++p)
+//----------------------------------------------------------------------------
+bool cmFindPackageCommand::FindAppBundleConfig()
+{
+  for(std::vector<std::string>::const_iterator i = this->Prefixes.begin();
+      i != this->Prefixes.end(); ++i)
     {
-    std::string prefix = *p;
-    for(std::vector<cmStdString>::const_iterator r = this->Relatives.begin();
-        r != this->Relatives.end(); ++r)
+    if(this->SearchAppBundlePrefix(*i))
       {
-      std::string dir = prefix;
-      dir += *r;
-      std::string f = dir;
-      f += "/";
-      f += this->Config;
-      if(cmSystemTools::FileExists(f.c_str()))
-        {
-        return dir;
-        }
+      return true;
       }
     }
-
-  return this->Variable + "-NOTFOUND";
+  return false;
 }
 
 //----------------------------------------------------------------------------
@@ -480,7 +758,7 @@ void cmFindPackageCommand::AppendToProperty(const char* propertyName)
  }
 
 //----------------------------------------------------------------------------
-void cmFindPackageCommand::AppendSuccessInformation(bool quiet)
+void cmFindPackageCommand::AppendSuccessInformation()
 {
   std::string found = this->Name;
   found += "_FOUND";
@@ -491,7 +769,7 @@ void cmFindPackageCommand::AppendSuccessInformation(bool quiet)
   if ((cmSystemTools::IsOn(result)) || (cmSystemTools::IsOn(upperResult)))
     {
     this->AppendToProperty("PACKAGES_FOUND");
-    if (!quiet)
+    if (!this->Quiet)
       {
       this->AppendToProperty("ENABLED_FEATURES");
       }
@@ -499,9 +777,725 @@ void cmFindPackageCommand::AppendSuccessInformation(bool quiet)
   else
     {
     this->AppendToProperty("PACKAGES_NOT_FOUND");
-    if (!quiet)
+    if (!this->Quiet)
       {
       this->AppendToProperty("DISABLED_FEATURES");
       }
     }
 }
+
+//----------------------------------------------------------------------------
+void cmFindPackageCommand::AddUserPath(std::string const& p)
+{
+  std::string userPath = p;
+  cmSystemTools::ExpandRegistryValues(userPath);
+  this->UserPaths.push_back(userPath);
+}
+
+//----------------------------------------------------------------------------
+void cmFindPackageCommand::ComputePrefixes()
+{
+  std::vector<std::string>& prefixes = this->Prefixes;
+  std::set<cmStdString> emmitted;
+
+  if(!this->NoCMakeEnvironmentPath && !this->NoDefaultPath)
+    {
+    // Check the environment variable with the same name as the cache
+    // entry.
+    std::string env;
+    if(cmSystemTools::GetEnv(this->Variable.c_str(), env) && env.length() > 0)
+      {
+      cmSystemTools::ConvertToUnixSlashes(env);
+      this->AddPathInternal(prefixes, env, EnvPath, &emmitted);
+      }
+
+    this->AddEnvPath(prefixes, "CMAKE_PREFIX_PATH", &emmitted);
+    this->AddEnvPath(prefixes, "CMAKE_FRAMEWORK_PATH", &emmitted);
+    this->AddEnvPath(prefixes, "CMAKE_APPBUNDLE_PATH", &emmitted);
+    }
+
+  if(!this->NoCMakePath && !this->NoDefaultPath)
+    {
+    this->AddCMakePath(prefixes, "CMAKE_PREFIX_PATH", &emmitted);
+    this->AddCMakePath(prefixes, "CMAKE_FRAMEWORK_PATH", &emmitted);
+    this->AddCMakePath(prefixes, "CMAKE_APPBUNDLE_PATH", &emmitted);
+    }
+
+  if(!this->NoSystemEnvironmentPath && !this->NoDefaultPath)
+    {
+    // Use the system search path to generate prefixes.
+    // Relative paths are interpreted with respect to the current
+    // working directory.
+    std::vector<std::string> tmp;
+    cmSystemTools::GetPath(tmp);
+    for(std::vector<std::string>::iterator i = tmp.begin();
+        i != tmp.end(); ++i)
+      {
+      std::string const& d = *i;
+
+      // If the path is a PREFIX/bin case then add its parent instead.
+      if(d.size() >= 4 && strcmp(d.c_str()+d.size()-4, "/bin") == 0 ||
+         d.size() >= 5 && strcmp(d.c_str()+d.size()-5, "/sbin") == 0)
+        {
+        this->AddPathInternal(prefixes,
+                              cmSystemTools::GetFilenamePath(d),
+                              EnvPath, &emmitted);
+        }
+      else
+        {
+        this->AddPathInternal(prefixes, d, EnvPath, &emmitted);
+        }
+      }
+    }
+
+  if(!this->NoBuilds && !this->NoDefaultPath)
+    {
+    // It is likely that CMake will have recently built the project.
+    for(int i=1; i <= 10; ++i)
+      {
+      cmOStringStream r;
+      r <<
+        "[HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\"
+        "Settings\\StartPath;WhereBuild" << i << "]";
+      std::string f = r.str();
+      cmSystemTools::ExpandRegistryValues(f);
+      cmSystemTools::ConvertToUnixSlashes(f);
+      if(cmSystemTools::FileIsFullPath(f.c_str()) &&
+         cmSystemTools::FileIsDirectory(f.c_str()))
+        {
+        this->AddPathInternal(prefixes, f, FullPath, &emmitted);
+        }
+      }
+    }
+
+  if(!this->NoCMakeSystemPath && !this->NoDefaultPath)
+    {
+    this->AddCMakePath(prefixes, "CMAKE_SYSTEM_PREFIX_PATH", &emmitted);
+    this->AddCMakePath(prefixes, "CMAKE_SYSTEM_FRAMEWORK_PATH", &emmitted);
+    this->AddCMakePath(prefixes, "CMAKE_SYSTEM_APPBUNDLE_PATH", &emmitted);
+    }
+
+  if(!this->UserPaths.empty())
+    {
+    // Add paths specified by the caller.
+    this->AddPathsInternal(prefixes, this->UserPaths, CMakePath, &emmitted);
+    }
+
+  // Construct the final set of prefixes.
+  this->RerootPaths(prefixes);
+
+  // Add a trailing slash to all prefixes to aid the search process.
+  for(std::vector<std::string>::iterator i = prefixes.begin();
+      i != prefixes.end(); ++i)
+    {
+    std::string& prefix = *i;
+    if(prefix[prefix.size()-1] != '/')
+      {
+      prefix += "/";
+      }
+    }
+}
+
+//----------------------------------------------------------------------------
+bool cmFindPackageCommand::SearchDirectory(std::string const& dir)
+{
+  assert(!dir.empty() && dir[dir.size()-1] == '/');
+
+  // Check each path suffix on this directory.
+  for(std::vector<std::string>::const_iterator
+        si = this->SearchPathSuffixes.begin();
+      si != this->SearchPathSuffixes.end(); ++si)
+    {
+    std::string d = dir;
+    if(!si->empty())
+      {
+      d += *si;
+      d += "/";
+      }
+    if(this->CheckDirectory(d))
+      {
+      return true;
+      }
+    }
+  return false;
+}
+
+//----------------------------------------------------------------------------
+bool cmFindPackageCommand::CheckDirectory(std::string const& dir)
+{
+  assert(!dir.empty() && dir[dir.size()-1] == '/');
+
+  // Look for the file in this directory.
+  std::string d = dir.substr(0, dir.size()-1);
+  if(this->FindConfigFile(d, this->FileFound))
+    {
+    return true;
+    }
+  return false;
+}
+
+//----------------------------------------------------------------------------
+bool cmFindPackageCommand::FindConfigFile(std::string const& dir,
+                                          std::string& file)
+{
+  for(std::vector<std::string>::const_iterator ci = this->Configs.begin();
+      ci != this->Configs.end(); ++ci)
+    {
+    file = dir;
+    file += "/";
+    file += *ci;
+    if(this->DebugMode)
+      {
+      fprintf(stderr, "Checking file [%s]\n", file.c_str());
+      }
+    if(cmSystemTools::FileExists(file.c_str(), true))
+      {
+      return true;
+      }
+    }
+  return false;
+}
+
+//----------------------------------------------------------------------------
+#include <cmsys/Directory.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/String.h>
+#include <cmsys/auto_ptr.hxx>
+
+class cmFileList;
+class cmFileListGeneratorBase
+{
+protected:
+  bool Consider(std::string const& fullPath, cmFileList& listing);
+private:
+  bool Search(cmFileList&);
+  virtual bool Search(std::string const& parent, cmFileList&) = 0;
+  virtual cmsys::auto_ptr<cmFileListGeneratorBase> Clone() const = 0;
+  friend class cmFileList;
+  cmFileListGeneratorBase* SetNext(cmFileListGeneratorBase const& next);
+  cmsys::auto_ptr<cmFileListGeneratorBase> Next;
+};
+
+class cmFileList
+{
+public:
+  cmFileList(): First(), Last(0) {}
+  cmFileList& operator/(cmFileListGeneratorBase const& rhs)
+    {
+    if(this->Last)
+      {
+      this->Last = this->Last->SetNext(rhs);
+      }
+    else
+      {
+      this->First = rhs.Clone();
+      this->Last = this->First.get();
+      }
+    return *this;
+    }
+  bool Search()
+    {
+    if(this->First.get())
+      {
+      return this->First->Search(*this);
+      }
+    return false;
+    }
+private:
+  virtual bool Visit(std::string const& fullPath) = 0;
+  friend class cmFileListGeneratorBase;
+  cmsys::auto_ptr<cmFileListGeneratorBase> First;
+  cmFileListGeneratorBase* Last;
+};
+
+class cmFindPackageFileList: public cmFileList
+{
+public:
+  cmFindPackageFileList(cmFindPackageCommand* fpc,
+                        bool use_suffixes = true):
+    cmFileList(), FPC(fpc), UseSuffixes(use_suffixes) {}
+private:
+  bool Visit(std::string const& fullPath)
+    {
+    if(this->UseSuffixes)
+      {
+      return this->FPC->SearchDirectory(fullPath);
+      }
+    else
+      {
+      return this->FPC->CheckDirectory(fullPath);
+      }
+    }
+  cmFindPackageCommand* FPC;
+  bool UseSuffixes;
+};
+
+bool cmFileListGeneratorBase::Search(cmFileList& listing)
+{
+  return this->Search("", listing);
+}
+
+cmFileListGeneratorBase*
+cmFileListGeneratorBase::SetNext(cmFileListGeneratorBase const& next)
+{
+  this->Next = next.Clone();
+  return this->Next.get();
+}
+
+bool cmFileListGeneratorBase::Consider(std::string const& fullPath,
+                                       cmFileList& listing)
+{
+  if(this->Next.get())
+    {
+    return this->Next->Search(fullPath + "/", listing);
+    }
+  else
+    {
+    return listing.Visit(fullPath + "/");
+    }
+}
+
+class cmFileListGeneratorFixed: public cmFileListGeneratorBase
+{
+public:
+  cmFileListGeneratorFixed(std::string const& str):
+    cmFileListGeneratorBase(), String(str) {}
+  cmFileListGeneratorFixed(cmFileListGeneratorFixed const& r):
+    cmFileListGeneratorBase(), String(r.String) {}
+private:
+  std::string String;
+  virtual bool Search(std::string const& parent, cmFileList& lister)
+    {
+    std::string fullPath = parent + this->String;
+    return this->Consider(fullPath, lister);
+    }
+  virtual cmsys::auto_ptr<cmFileListGeneratorBase> Clone() const
+    {
+    cmsys::auto_ptr<cmFileListGeneratorBase>
+      g(new cmFileListGeneratorFixed(*this));
+    return g;
+    }
+};
+
+class cmFileListGeneratorEnumerate: public cmFileListGeneratorBase
+{
+public:
+  cmFileListGeneratorEnumerate(const char* p1, const char* p2):
+    cmFileListGeneratorBase()
+    {
+    this->Vector.push_back(p1);
+    this->Vector.push_back(p2);
+    }
+  cmFileListGeneratorEnumerate(cmFileListGeneratorEnumerate const& r):
+    cmFileListGeneratorBase(), Vector(r.Vector) {}
+private:
+  std::vector<std::string> Vector;
+  virtual bool Search(std::string const& parent, cmFileList& lister)
+    {
+    for(std::vector<std::string>::const_iterator i = this->Vector.begin();
+        i != this->Vector.end(); ++i)
+      {
+      if(this->Consider(parent + *i, lister))
+        {
+        return true;
+        }
+      }
+    return false;
+    }
+  virtual cmsys::auto_ptr<cmFileListGeneratorBase> Clone() const
+    {
+    cmsys::auto_ptr<cmFileListGeneratorBase>
+      g(new cmFileListGeneratorEnumerate(*this));
+    return g;
+    }
+};
+
+class cmFileListGeneratorProject: public cmFileListGeneratorBase
+{
+public:
+  cmFileListGeneratorProject(std::vector<std::string> const& names):
+    cmFileListGeneratorBase(), Names(names) {}
+  cmFileListGeneratorProject(cmFileListGeneratorProject const& r):
+    cmFileListGeneratorBase(), Names(r.Names) {}
+private:
+  std::vector<std::string> const& Names;
+  virtual bool Search(std::string const& parent, cmFileList& lister)
+    {
+    // Construct a list of matches.
+    std::vector<std::string> matches;
+    cmsys::Directory d;
+    d.Load(parent.c_str());
+    for(unsigned long i=0; i < d.GetNumberOfFiles(); ++i)
+      {
+      const char* fname = d.GetFile(i);
+      if(strcmp(fname, ".") == 0 ||
+         strcmp(fname, "..") == 0)
+        {
+        continue;
+        }
+      for(std::vector<std::string>::const_iterator ni = this->Names.begin();
+          ni != this->Names.end(); ++ni)
+        {
+        if(cmsysString_strncasecmp(fname, ni->c_str(),
+                                   ni->length()) == 0)
+          {
+          matches.push_back(fname);
+          }
+        }
+      }
+
+    for(std::vector<std::string>::const_iterator i = matches.begin();
+        i != matches.end(); ++i)
+      {
+      if(this->Consider(parent + *i, lister))
+        {
+        return true;
+        }
+      }
+    return false;
+    }
+  virtual cmsys::auto_ptr<cmFileListGeneratorBase> Clone() const
+    {
+    cmsys::auto_ptr<cmFileListGeneratorBase>
+      g(new cmFileListGeneratorProject(*this));
+    return g;
+    }
+};
+
+class cmFileListGeneratorMacProject: public cmFileListGeneratorBase
+{
+public:
+  cmFileListGeneratorMacProject(std::vector<std::string> const& names,
+                                const char* ext):
+    cmFileListGeneratorBase(), Names(names), Extension(ext) {}
+  cmFileListGeneratorMacProject(cmFileListGeneratorMacProject const& r):
+    cmFileListGeneratorBase(), Names(r.Names), Extension(r.Extension) {}
+private:
+  std::vector<std::string> const& Names;
+  std::string Extension;
+  virtual bool Search(std::string const& parent, cmFileList& lister)
+    {
+    // Construct a list of matches.
+    std::vector<std::string> matches;
+    cmsys::Directory d;
+    d.Load(parent.c_str());
+    for(unsigned long i=0; i < d.GetNumberOfFiles(); ++i)
+      {
+      const char* fname = d.GetFile(i);
+      if(strcmp(fname, ".") == 0 ||
+         strcmp(fname, "..") == 0)
+        {
+        continue;
+        }
+      for(std::vector<std::string>::const_iterator ni = this->Names.begin();
+          ni != this->Names.end(); ++ni)
+        {
+        std::string name = *ni;
+        name += this->Extension;
+        if(cmsysString_strcasecmp(fname, name.c_str()) == 0)
+          {
+          matches.push_back(fname);
+          }
+        }
+      }
+
+    for(std::vector<std::string>::const_iterator i = matches.begin();
+        i != matches.end(); ++i)
+      {
+      if(this->Consider(parent + *i, lister))
+        {
+        return true;
+        }
+      }
+    return false;
+    }
+  virtual cmsys::auto_ptr<cmFileListGeneratorBase> Clone() const
+    {
+    cmsys::auto_ptr<cmFileListGeneratorBase>
+      g(new cmFileListGeneratorMacProject(*this));
+    return g;
+    }
+};
+
+class cmFileListGeneratorCaseInsensitive: public cmFileListGeneratorBase
+{
+public:
+  cmFileListGeneratorCaseInsensitive(std::string const& str):
+    cmFileListGeneratorBase(), String(str) {}
+  cmFileListGeneratorCaseInsensitive(cmFileListGeneratorCaseInsensitive const& r):
+    cmFileListGeneratorBase(), String(r.String) {}
+private:
+  std::string String;
+  virtual bool Search(std::string const& parent, cmFileList& lister)
+    {
+    // Look for matching files.
+    std::vector<std::string> matches;
+    cmsys::Directory d;
+    d.Load(parent.c_str());
+    for(unsigned long i=0; i < d.GetNumberOfFiles(); ++i)
+      {
+      const char* fname = d.GetFile(i);
+      if(strcmp(fname, ".") == 0 ||
+         strcmp(fname, "..") == 0)
+        {
+        continue;
+        }
+      if(cmsysString_strcasecmp(fname, this->String.c_str()) == 0)
+        {
+        if(this->Consider(parent + fname, lister))
+          {
+          return true;
+          }
+        }
+      }
+    return false;
+    }
+  virtual cmsys::auto_ptr<cmFileListGeneratorBase> Clone() const
+    {
+    cmsys::auto_ptr<cmFileListGeneratorBase>
+      g(new cmFileListGeneratorCaseInsensitive(*this));
+    return g;
+    }
+};
+
+class cmFileListGeneratorGlob: public cmFileListGeneratorBase
+{
+public:
+  cmFileListGeneratorGlob(std::string const& str):
+    cmFileListGeneratorBase(), Pattern(str) {}
+  cmFileListGeneratorGlob(cmFileListGeneratorGlob const& r):
+    cmFileListGeneratorBase(), Pattern(r.Pattern) {}
+private:
+  std::string Pattern;
+  virtual bool Search(std::string const& parent, cmFileList& lister)
+    {
+    // Glob the set of matching files.
+    std::string expr = parent;
+    expr += this->Pattern;
+    cmsys::Glob g;
+    if(!g.FindFiles(expr))
+      {
+      return false;
+      }
+    std::vector<std::string> const& files = g.GetFiles();
+
+    // Look for directories among the matches.
+    for(std::vector<std::string>::const_iterator fi = files.begin();
+        fi != files.end(); ++fi)
+      {
+      if(cmSystemTools::FileIsDirectory(fi->c_str()))
+        {
+        if(this->Consider(*fi, lister))
+          {
+          return true;
+          }
+        }
+      }
+    return false;
+    }
+  virtual cmsys::auto_ptr<cmFileListGeneratorBase> Clone() const
+    {
+    cmsys::auto_ptr<cmFileListGeneratorBase>
+      g(new cmFileListGeneratorGlob(*this));
+    return g;
+    }
+};
+
+//----------------------------------------------------------------------------
+bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in)
+{
+  assert(!prefix_in.empty() && prefix_in[prefix_in.size()-1] == '/');
+  if(this->DebugMode)
+    {
+    fprintf(stderr, "Checking prefix [%s]\n", prefix_in.c_str());
+    }
+
+  // Skip this if the prefix does not exist.
+  if(!cmSystemTools::FileIsDirectory(prefix_in.c_str()))
+    {
+    return false;
+    }
+
+  //  PREFIX/ (useful on windows or in build trees)
+  if(this->SearchDirectory(prefix_in))
+    {
+    return true;
+    }
+
+  // Strip the trailing slash because the path generator is about to
+  // add one.
+  std::string prefix = prefix_in.substr(0, prefix_in.size()-1);
+
+  //  PREFIX/(cmake|CMake)/ (useful on windows or in build trees)
+  {
+  cmFindPackageFileList lister(this);
+  lister
+    / cmFileListGeneratorFixed(prefix)
+    / cmFileListGeneratorCaseInsensitive("cmake");
+  if(lister.Search())
+    {
+    return true;
+    }
+  }
+
+  //  PREFIX/(share|lib)/(Foo|foo|FOO).*/
+  {
+  cmFindPackageFileList lister(this);
+  lister
+    / cmFileListGeneratorFixed(prefix)
+    / cmFileListGeneratorEnumerate("lib", "share")
+    / cmFileListGeneratorProject(this->Names);
+  if(lister.Search())
+    {
+    return true;
+    }
+  }
+
+  //  PREFIX/(share|lib)/(Foo|foo|FOO).*/(cmake|CMake)/
+  {
+  cmFindPackageFileList lister(this);
+  lister
+    / cmFileListGeneratorFixed(prefix)
+    / cmFileListGeneratorEnumerate("lib", "share")
+    / cmFileListGeneratorProject(this->Names)
+    / cmFileListGeneratorCaseInsensitive("cmake");
+  if(lister.Search())
+    {
+    return true;
+    }
+  }
+
+  return false;
+}
+
+//----------------------------------------------------------------------------
+bool cmFindPackageCommand::SearchFrameworkPrefix(std::string const& prefix_in)
+{
+  assert(!prefix_in.empty() && prefix_in[prefix_in.size()-1] == '/');
+  if(this->DebugMode)
+    {
+    fprintf(stderr, "Checking framework prefix [%s]\n", prefix_in.c_str());
+    }
+
+  // Strip the trailing slash because the path generator is about to
+  // add one.
+  std::string prefix = prefix_in.substr(0, prefix_in.size()-1);
+
+  // <prefix>/Foo.framework/Resources/
+  {
+  cmFindPackageFileList lister(this);
+  lister
+    / cmFileListGeneratorFixed(prefix)
+    / cmFileListGeneratorMacProject(this->Names, ".framework")
+    / cmFileListGeneratorFixed("Resources");
+  if(lister.Search())
+    {
+    return true;
+    }
+  }
+  // <prefix>/Foo.framework/Resources/CMake/
+  {
+  cmFindPackageFileList lister(this);
+  lister
+    / cmFileListGeneratorFixed(prefix)
+    / cmFileListGeneratorMacProject(this->Names, ".framework")
+    / cmFileListGeneratorFixed("Resources")
+    / cmFileListGeneratorCaseInsensitive("cmake");
+  if(lister.Search())
+    {
+    return true;
+    }
+  }
+
+  // <prefix>/Foo.framework/Versions/*/Resources/
+  {
+  cmFindPackageFileList lister(this);
+  lister
+    / cmFileListGeneratorFixed(prefix)
+    / cmFileListGeneratorMacProject(this->Names, ".framework")
+    / cmFileListGeneratorFixed("Versions")
+    / cmFileListGeneratorGlob("*/Resources");
+  if(lister.Search())
+    {
+    return true;
+    }
+  }
+
+  // <prefix>/Foo.framework/Versions/*/Resources/CMake/
+  {
+  cmFindPackageFileList lister(this);
+  lister
+    / cmFileListGeneratorFixed(prefix)
+    / cmFileListGeneratorMacProject(this->Names, ".framework")
+    / cmFileListGeneratorFixed("Versions")
+    / cmFileListGeneratorGlob("*/Resources")
+    / cmFileListGeneratorCaseInsensitive("cmake");
+  if(lister.Search())
+    {
+    return true;
+    }
+  }
+
+  return false;
+}
+
+//----------------------------------------------------------------------------
+bool cmFindPackageCommand::SearchAppBundlePrefix(std::string const& prefix_in)
+{
+  assert(!prefix_in.empty() && prefix_in[prefix_in.size()-1] == '/');
+  if(this->DebugMode)
+    {
+    fprintf(stderr, "Checking bundle prefix [%s]\n", prefix_in.c_str());
+    }
+
+  // Strip the trailing slash because the path generator is about to
+  // add one.
+  std::string prefix = prefix_in.substr(0, prefix_in.size()-1);
+
+  // <prefix>/Foo.app/Contents/Resources
+  {
+  cmFindPackageFileList lister(this);
+  lister
+    / cmFileListGeneratorFixed(prefix)
+    / cmFileListGeneratorMacProject(this->Names, ".app")
+    / cmFileListGeneratorFixed("Contents/Resources");
+  if(lister.Search())
+    {
+    return true;
+    }
+  }
+
+  // <prefix>/Foo.app/Contents/Resources/CMake
+  {
+  cmFindPackageFileList lister(this);
+  lister
+    / cmFileListGeneratorFixed(prefix)
+    / cmFileListGeneratorMacProject(this->Names, ".app")
+    / cmFileListGeneratorFixed("Contents/Resources")
+    / cmFileListGeneratorCaseInsensitive("cmake");
+  if(lister.Search())
+    {
+    return true;
+    }
+  }
+
+  return false;
+}
+
+// TODO: Version numbers?  Perhaps have a listing component class that
+// sorts by lexicographic and numerical ordering.  Also try to match
+// some command argument for the version.  Alternatively provide an
+// API that just returns a list of valid directories?  Perhaps push a
+// scope and try loading the target file just to get its version
+// number?  Could add a foo-version.cmake or FooVersion.cmake file
+// in the projects that contains just version information.
+
+// TODO: Debug cmsys::Glob double slash problem.
+
+// TODO: Add registry entries after cmake system search path?
+// Currently the user must specify them with the PATHS option.
+//
+//  [HKEY_CURRENT_USER\Software\*\Foo*;InstallDir]
+//  [HKEY_CURRENT_USER\Software\*\*\Foo*;InstallDir]
+//  [HKEY_LOCAL_MACHINE\Software\*\Foo*;InstallDir]
+//  [HKEY_LOCAL_MACHINE\Software\*\*\Foo*;InstallDir]

+ 38 - 40
Source/cmFindPackageCommand.h

@@ -17,16 +17,20 @@
 #ifndef cmFindPackageCommand_h
 #define cmFindPackageCommand_h
 
-#include "cmCommand.h"
+#include "cmFindCommon.h"
+
+class cmFindPackageFileList;
 
 /** \class cmFindPackageCommand
  * \brief Load settings from an external project.
  *
  * cmFindPackageCommand
  */
-class cmFindPackageCommand : public cmCommand
+class cmFindPackageCommand : public cmFindCommon
 {
 public:
+  cmFindPackageCommand();
+
   /**
    * This is a virtual constructor for the command.
    */
@@ -62,51 +66,45 @@ public:
   /**
    * More documentation.
    */
-  virtual const char* GetFullDocumentation()
-    {
-    return
-      "  find_package(<name> [major.minor] [QUIET] [NO_MODULE]\n"
-      "               [[REQUIRED|COMPONENTS] [components...]])\n"
-      "Finds and loads settings from an external project.  <name>_FOUND will "
-      "be set to indicate whether the package was found.  Settings that "
-      "can be used when <name>_FOUND is true are package-specific.  The "
-      "package is found through several steps.  "
-      "Directories listed in CMAKE_MODULE_PATH are searched for files called "
-      "\"Find<name>.cmake\".  If such a file is found, it is read and "
-      "processed by CMake, and is responsible for finding the package.  "
-      "This first step may be skipped by using the NO_MODULE option.  "
-      "If no such file is found, it is expected that the package is another "
-      "project built by CMake that has a \"<name>Config.cmake\" file.  "
-      "A cache entry called <name>_DIR is created and is expected to be set "
-      "to the directory containing this file.  If the file is found, it is "
-      "read and processed by CMake to load the settings of the package.  If "
-      "<name>_DIR has not been set during a configure step, the command "
-      "will generate an error describing the problem unless the QUIET "
-      "argument is specified.  If <name>_DIR has been set to a directory "
-      "not containing a \"<name>Config.cmake\" file, an error is always "
-      "generated.  If REQUIRED is specified and the package is not found, "
-      "a FATAL_ERROR is generated and the configure step stops executing.  "
-      "A package-specific list of components may be listed after the "
-      "REQUIRED option, or after the COMPONENTS option if no REQUIRED "
-      "option is given.";
-    }
+  virtual const char* GetFullDocumentation();
 
-  cmTypeMacro(cmFindPackageCommand, cmCommand);
+  cmTypeMacro(cmFindPackageCommand, cmFindCommon);
 private:
-  void AppendSuccessInformation(bool quiet);
+  void AppendSuccessInformation();
   void AppendToProperty(const char* propertyName);
-  bool FindModule(bool& found, bool quiet, bool required);
-  bool FindConfig();
-  std::string SearchForConfig() const;
+  bool FindModule(bool& found);
+  bool HandlePackageMode();
+  void FindConfig();
+  bool FindPrefixedConfig();
+  bool FindFrameworkConfig();
+  bool FindAppBundleConfig();
   bool ReadListFile(const char* f);
 
+  void AddUserPath(std::string const& p);
+  void ComputePrefixes();
+  bool SearchDirectory(std::string const& dir);
+  bool CheckDirectory(std::string const& dir);
+  bool FindConfigFile(std::string const& dir, std::string& file);
+  bool SearchPrefix(std::string const& prefix);
+  bool SearchFrameworkPrefix(std::string const& prefix_in);
+  bool SearchAppBundlePrefix(std::string const& prefix_in);
+
+  friend class cmFindPackageFileList;
+
+  std::string CommandDocumentation;
   cmStdString Name;
   cmStdString Variable;
-  cmStdString Config;
-  std::vector<cmStdString> Builds;
-  std::vector<cmStdString> Prefixes;
-  std::vector<cmStdString> Relatives;
+  cmStdString FileFound;
+  bool Quiet;
+  bool Required;
+  bool Compatibility_1_6;
+  bool NoModule;
+  bool NoBuilds;
+  bool DebugMode;
+  std::vector<std::string> Names;
+  std::vector<std::string> Configs;
+  std::vector<std::string> Prefixes;
+  std::vector<std::string> UserPaths;
 };
 
-
 #endif

+ 6 - 0
Source/cmFindPathCommand.cxx

@@ -27,6 +27,12 @@ cmFindPathCommand::cmFindPathCommand()
                                "FIND_XXX", "find_path");
   cmSystemTools::ReplaceString(this->GenericDocumentation,
                                "CMAKE_XXX_PATH", "CMAKE_INCLUDE_PATH");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "CMAKE_XXX_MAC_PATH",
+                               "CMAKE_FRAMEWORK_PATH");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "CMAKE_SYSTEM_XXX_MAC_PATH",
+                               "CMAKE_SYSTEM_FRAMEWORK_PATH");
   cmSystemTools::ReplaceString(this->GenericDocumentation,
                                "XXX_SYSTEM", "INCLUDE");
   cmSystemTools::ReplaceString(this->GenericDocumentation,

+ 6 - 0
Source/cmFindProgramCommand.cxx

@@ -28,6 +28,12 @@ cmFindProgramCommand::cmFindProgramCommand()
                                "FIND_XXX", "find_program");
   cmSystemTools::ReplaceString(this->GenericDocumentation,
                                "CMAKE_XXX_PATH", "CMAKE_PROGRAM_PATH");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "CMAKE_XXX_MAC_PATH",
+                               "CMAKE_APPBUNDLE_PATH");
+  cmSystemTools::ReplaceString(this->GenericDocumentation,
+                               "CMAKE_SYSTEM_XXX_MAC_PATH",
+                               "CMAKE_SYSTEM_APPBUNDLE_PATH");
   cmSystemTools::ReplaceString(this->GenericDocumentation,
                                "XXX_SYSTEM", "");
   cmSystemTools::ReplaceString(this->GenericDocumentation,