Browse Source

Encapsulate search path manipulation functions into a seperate class.

The functions for adding the various different types of paths have been
factored out into a new class, cmSearchPath.  It is to be used as a helper
container class for the various find_* commands.
Chuck Atkins 11 năm trước cách đây
mục cha
commit
2a9ac4bd83

+ 1 - 0
Source/cmBootstrapCommands1.cxx

@@ -43,6 +43,7 @@
 #include "cmExecuteProcessCommand.cxx"
 #include "cmExternalMakefileProjectGenerator.cxx"
 #include "cmFindBase.cxx"
+#include "cmSearchPath.cxx"
 #include "cmFindCommon.cxx"
 #include "cmFileCommand.cxx"
 #include "cmFindFileCommand.cxx"

+ 34 - 143
Source/cmFindBase.cxx

@@ -140,11 +140,11 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
       }
     else if(doing == DoingPaths)
       {
-      this->AddUserPath(args[j], this->UserGuessPaths);
+      this->UserGuessArgs.push_back(args[j]);
       }
     else if(doing == DoingHints)
       {
-      this->AddUserPath(args[j], this->UserHintsPaths);
+      this->UserHintsArgs.push_back(args[j]);
       }
     else if(doing == DoingPathSuffixes)
       {
@@ -186,7 +186,7 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
     this->Names.push_back(shortArgs[0]);
     for(unsigned int j = 1; j < shortArgs.size(); ++j)
       {
-      this->AddUserPath(shortArgs[j], this->UserGuessPaths);
+      this->UserGuessArgs.push_back(shortArgs[j]);
       }
     }
   this->ExpandPaths();
@@ -203,107 +203,23 @@ void cmFindBase::ExpandPaths()
     if(!this->NoCMakePath)
       {
       this->FillCMakeVariablePath();
-      this->AddPathSuffixes(this->CMakeVariablePaths);
       }
     if(!this->NoCMakeEnvironmentPath)
       {
       this->FillCMakeEnvironmentPath();
-      this->AddPathSuffixes(this->CMakeEnvironmentPaths);
       }
     if(!this->NoSystemEnvironmentPath)
       {
       this->FillSystemEnvironmentPath();
-      this->AddPathSuffixes(this->SystemEnvironmentPaths);
       }
     if(!this->NoCMakeSystemPath)
       {
       this->FillCMakeSystemVariablePath();
-      this->AddPathSuffixes(this->CMakeSystemVariablePaths);
       }
     }
 
   this->FillUserHintsPath();
-  this->AddPathSuffixes(this->UserHintsPaths);
   this->FillUserGuessPath();
-  this->AddPathSuffixes(this->UserGuessPaths);
-}
-
-//----------------------------------------------------------------------------
-void cmFindBase::AddPrefixPaths(std::vector<std::string> const& inPaths,
-                                PathType pt,
-                                std::vector<std::string>& outPaths)
-{
-  // default for programs
-  std::string subdir = "bin";
-
-  if (this->CMakePathName == "INCLUDE")
-    {
-    subdir = "include";
-    }
-  else if (this->CMakePathName == "LIBRARY")
-    {
-    subdir = "lib";
-    }
-  else if (this->CMakePathName == "FRAMEWORK")
-    {
-    subdir = "";  // ? what to do for frameworks ?
-    }
-
-  for(std::vector<std::string>::const_iterator it = inPaths.begin();
-      it != inPaths.end(); ++it)
-    {
-    std::string dir = *it;
-    if(!subdir.empty() && !dir.empty() && dir[dir.size()-1] != '/')
-      {
-      dir += "/";
-      }
-    if(subdir == "include" || subdir == "lib")
-      {
-      const char* arch =
-        this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE");
-      if(arch && *arch)
-        {
-        this->AddPathInternal(this->MakeFullPath(dir+subdir+"/"+arch, pt),
-                              outPaths);
-        }
-      }
-    std::string add = dir + subdir;
-    if(add != "/")
-      {
-      this->AddPathInternal(this->MakeFullPath(add, pt), outPaths);
-      }
-    if (subdir == "bin")
-      {
-      this->AddPathInternal(this->MakeFullPath(dir+"sbin", pt), outPaths);
-      }
-    if(!subdir.empty() && *it != "/")
-      {
-      this->AddPathInternal(this->MakeFullPath(*it, pt), outPaths);
-      }
-    }
-}
-
-//----------------------------------------------------------------------------
-void cmFindBase::AddCMakePrefixPath(const std::string& variable,
-                                    std::vector<std::string>& outPaths)
-{
-  // Get a path from a CMake variable.
-  if(const char* varPath = this->Makefile->GetDefinition(variable))
-    {
-    std::vector<std::string> tmp;
-    cmSystemTools::ExpandListArgument(varPath, tmp);
-    this->AddPrefixPaths(tmp, CMakePath, outPaths);
-    }
-}
-
-//----------------------------------------------------------------------------
-void cmFindBase::AddEnvPrefixPath(const std::string& variable,
-                                  std::vector<std::string>& outPaths)
-{
-  // Get a path from the environment.
-  std::vector<std::string> tmp;
-  cmSystemTools::GetPath(tmp, variable.c_str());
-  this->AddPrefixPaths(tmp, EnvPath, outPaths);
 }
 
 //----------------------------------------------------------------------------
@@ -313,17 +229,18 @@ void cmFindBase::FillCMakeEnvironmentPath()
   std::string var = "CMAKE_";
   var += this->CMakePathName;
   var += "_PATH";
-  this->AddEnvPrefixPath("CMAKE_PREFIX_PATH", this->CMakeEnvironmentPaths);
-  this->AddEnvPath(var.c_str(), this->CMakeEnvironmentPaths);
+  this->CMakeEnvironmentPaths.AddEnvPrefixPath("CMAKE_PREFIX_PATH");
+  this->CMakeEnvironmentPaths.AddEnvPath(var);
 
   if(this->CMakePathName == "PROGRAM")
     {
-    this->AddEnvPath("CMAKE_APPBUNDLE_PATH", this->CMakeEnvironmentPaths);
+    this->CMakeEnvironmentPaths.AddEnvPath("CMAKE_APPBUNDLE_PATH");
     }
   else
     {
-    this->AddEnvPath("CMAKE_FRAMEWORK_PATH", this->CMakeEnvironmentPaths);
+    this->CMakeEnvironmentPaths.AddEnvPath("CMAKE_FRAMEWORK_PATH");
     }
+  this->CMakeEnvironmentPaths.AddSuffixes(this->SearchPathSuffixes);
 }
 
 //----------------------------------------------------------------------------
@@ -335,17 +252,18 @@ void cmFindBase::FillCMakeVariablePath()
   std::string var = "CMAKE_";
   var += this->CMakePathName;
   var += "_PATH";
-  this->AddCMakePrefixPath("CMAKE_PREFIX_PATH", this->CMakeVariablePaths);
-  this->AddCMakePath(var, this->CMakeVariablePaths);
+  this->CMakeVariablePaths.AddCMakePrefixPath("CMAKE_PREFIX_PATH");
+  this->CMakeVariablePaths.AddCMakePath(var);
 
   if(this->CMakePathName == "PROGRAM")
     {
-    this->AddCMakePath("CMAKE_APPBUNDLE_PATH", this->CMakeVariablePaths);
+    this->CMakeVariablePaths.AddCMakePath("CMAKE_APPBUNDLE_PATH");
     }
   else
     {
-    this->AddCMakePath("CMAKE_FRAMEWORK_PATH", this->CMakeVariablePaths);
+    this->CMakeVariablePaths.AddCMakePath("CMAKE_FRAMEWORK_PATH");
     }
+  this->CMakeVariablePaths.AddSuffixes(this->SearchPathSuffixes);
 }
 
 //----------------------------------------------------------------------------
@@ -354,11 +272,11 @@ void cmFindBase::FillSystemEnvironmentPath()
   // Add LIB or INCLUDE
   if(!this->EnvironmentPath.empty())
     {
-    this->AddEnvPath(this->EnvironmentPath.c_str(),
-                     this->SystemEnvironmentPaths);
+    this->SystemEnvironmentPaths.AddEnvPath(this->EnvironmentPath);
     }
   // Add PATH
-  this->AddEnvPath(0, this->SystemEnvironmentPaths);
+  this->SystemEnvironmentPaths.AddEnvPath("PATH");
+  this->SystemEnvironmentPaths.AddSuffixes(this->SearchPathSuffixes);
 }
 
 //----------------------------------------------------------------------------
@@ -367,72 +285,45 @@ void cmFindBase::FillCMakeSystemVariablePath()
   std::string var = "CMAKE_SYSTEM_";
   var += this->CMakePathName;
   var += "_PATH";
-  this->AddCMakePrefixPath("CMAKE_SYSTEM_PREFIX_PATH",
-                           this->CMakeSystemVariablePaths);
-  this->AddCMakePath(var, this->CMakeSystemVariablePaths);
+  this->CMakeSystemVariablePaths.AddCMakePrefixPath(
+    "CMAKE_SYSTEM_PREFIX_PATH");
+  this->CMakeSystemVariablePaths.AddCMakePath(var);
 
   if(this->CMakePathName == "PROGRAM")
     {
-    this->AddCMakePath("CMAKE_SYSTEM_APPBUNDLE_PATH",
-                       this->CMakeSystemVariablePaths);
+    this->CMakeSystemVariablePaths.AddCMakePath(
+      "CMAKE_SYSTEM_APPBUNDLE_PATH");
     }
   else
     {
-    this->AddCMakePath("CMAKE_SYSTEM_FRAMEWORK_PATH",
-                       this->CMakeSystemVariablePaths);
+    this->CMakeSystemVariablePaths.AddCMakePath("CMAKE_SYSTEM_FRAMEWORK_PATH");
     }
+  this->CMakeSystemVariablePaths.AddSuffixes(this->SearchPathSuffixes);
 }
 
 //----------------------------------------------------------------------------
 void cmFindBase::FillUserHintsPath()
 {
-  std::vector<std::string> inPaths;
-  inPaths.swap(this->UserHintsPaths);
-  this->AddPathsInternal(inPaths, CMakePath, this->UserHintsPaths);
+  for(std::vector<std::string>::const_iterator p = this->UserHintsArgs.begin();
+      p != this->UserHintsArgs.end(); ++p)
+    {
+    this->UserHintsPaths.AddUserPath(*p);
+    }
+  this->UserHintsPaths.AddSuffixes(this->SearchPathSuffixes);
 }
 
 //----------------------------------------------------------------------------
 void cmFindBase::FillUserGuessPath()
 {
-  std::vector<std::string> inPaths;
-  inPaths.swap(this->UserGuessPaths);
-  this->AddPathsInternal(inPaths, CMakePath, this->UserGuessPaths);
-}
-
-//----------------------------------------------------------------------------
-void cmFindBase::AddPathSuffixes(std::vector<std::string>& paths)
-{
-  std::vector<std::string> inPaths;
-  inPaths.swap(paths);
-  paths.reserve(inPaths.size()*(this->SearchPathSuffixes.size()+1));
-
-  for(std::vector<std::string>::iterator ip = inPaths.begin();
-      ip != inPaths.end(); ++ip)
+  for(std::vector<std::string>::const_iterator p = this->UserGuessArgs.begin();
+      p != this->UserGuessArgs.end(); ++p)
     {
-    cmSystemTools::ConvertToUnixSlashes(*ip);
-
-    // if *i is only / then do not add a //
-    // this will get incorrectly considered a network
-    // path on windows and cause huge delays.
-    std::string p = *ip;
-    if(!p.empty() && *p.rbegin() != '/')
-      {
-      p += "/";
-      }
-
-    for(std::vector<std::string>::iterator sps =
-          this->SearchPathSuffixes.begin();
-        sps != this->SearchPathSuffixes.end(); ++sps)
-      {
-      // add to all paths because the search path may be modified
-      // later with lib being replaced for lib64 which may exist
-      paths.push_back(p+*sps);
-      }
-    // now put the path without the path suffixes in the SearchPaths
-    paths.push_back(*ip);
+    this->UserGuessPaths.AddUserPath(*p);
     }
+  this->UserGuessPaths.AddSuffixes(this->SearchPathSuffixes);
 }
 
+//----------------------------------------------------------------------------
 void cmFindBase::PrintFindStuff()
 {
   std::cerr << "SearchFrameworkLast: " << this->SearchFrameworkLast << "\n";

+ 0 - 9
Source/cmFindBase.h

@@ -34,7 +34,6 @@ public:
 protected:
   void PrintFindStuff();
   void ExpandPaths();
-  void AddPathSuffixes(std::vector<std::string>& paths);
 
   // see if the VariableName is already set in the cache,
   // also copy the documentation from the cache to VariableDocumentation
@@ -61,14 +60,6 @@ private:
   void FillSystemEnvironmentPath();
   void FillCMakeSystemVariablePath();
   void FillUserGuessPath();
-
-  // Helpers.
-  void AddCMakePrefixPath(const std::string& variable,
-                          std::vector<std::string>& outPaths);
-  void AddEnvPrefixPath(const std::string& variable,
-                        std::vector<std::string>& outPaths);
-  void AddPrefixPaths(std::vector<std::string> const& inPaths,
-                      PathType pathType, std::vector<std::string>& outPaths);
 };
 
 

+ 23 - 122
Source/cmFindCommon.cxx

@@ -15,6 +15,15 @@
 
 //----------------------------------------------------------------------------
 cmFindCommon::cmFindCommon()
+: CMakeVariablePaths(this, "CMAKE"),
+  CMakeEnvironmentPaths(this, "CMAKE_ENVIRONMENT"),
+  UserHintsPaths(this, "HINTS"),
+  SystemEnvironmentPaths(this, "SYSTEM_ENVIRONMENT"),
+  UserRegistryPaths(this, "USER_REGISTRY"),
+  BuildPaths(this, "BUILD"),
+  CMakeSystemVariablePaths(this, "CMAKE_SYSTEM_VARIABLE"),
+  SystemRegistryPaths(this, "SYSTEM_REGISTRY"),
+  UserGuessPaths(this, "GUESS")
 {
   this->FindRootPathMode = RootPathModeBoth;
   this->NoDefaultPath = false;
@@ -43,28 +52,9 @@ cmFindCommon::~cmFindCommon()
 {
 }
 
-//----------------------------------------------------------------------------
-std::string cmFindCommon::MakeFullPath(const std::string& path,
-                                       PathType pathType)
-{
-  // Select the base path with which to interpret relative paths.
-  if(pathType == CMakePath)
-    {
-    return cmSystemTools::CollapseFullPath(
-      path, this->Makefile->GetCurrentDirectory());
-    }
-  else
-    {
-    return cmSystemTools::CollapseFullPath(path, 0);
-    }
-}
-
 //----------------------------------------------------------------------------
 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;
@@ -72,11 +62,11 @@ void cmFindCommon::SelectDefaultRootPathMode()
     this->Makefile->GetSafeDefinition(findRootPathVar);
   if (rootPathMode=="NEVER")
     {
-    this->FindRootPathMode = RootPathModeNoRootPath;
+    this->FindRootPathMode = RootPathModeNever;
     }
   else if (rootPathMode=="ONLY")
     {
-    this->FindRootPathMode = RootPathModeOnlyRootPath;
+    this->FindRootPathMode = RootPathModeOnly;
     }
   else if (rootPathMode=="BOTH")
     {
@@ -152,7 +142,7 @@ void cmFindCommon::RerootPaths(std::vector<std::string>& paths)
 #endif
 
   // Short-circuit if there is nothing to do.
-  if(this->FindRootPathMode == RootPathModeNoRootPath)
+  if(this->FindRootPathMode == RootPathModeNever)
     {
     return;
     }
@@ -280,8 +270,6 @@ void cmFindCommon::GetIgnoredPaths(std::set<std::string>& ignore)
   ignore.insert(ignoreVec.begin(), ignoreVec.end());
 }
 
-
-
 //----------------------------------------------------------------------------
 bool cmFindCommon::CheckCommonArgument(std::string const& arg)
 {
@@ -307,11 +295,11 @@ bool cmFindCommon::CheckCommonArgument(std::string const& arg)
     }
   else if(arg == "NO_CMAKE_FIND_ROOT_PATH")
     {
-    this->FindRootPathMode = RootPathModeNoRootPath;
+    this->FindRootPathMode = RootPathModeNever;
     }
   else if(arg == "ONLY_CMAKE_FIND_ROOT_PATH")
     {
-    this->FindRootPathMode = RootPathModeOnlyRootPath;
+    this->FindRootPathMode = RootPathModeOnly;
     }
   else if(arg == "CMAKE_FIND_ROOT_PATH_BOTH")
     {
@@ -358,91 +346,6 @@ void cmFindCommon::AddPathSuffix(std::string const& arg)
   this->SearchPathSuffixes.push_back(suffix);
 }
 
-//----------------------------------------------------------------------------
-void cmFindCommon::AddUserPath(std::string const& inPath,
-                               std::vector<std::string>& outPaths)
-{
-  // We should view the registry as the target application would view
-  // it.
-  cmSystemTools::KeyWOW64 view = cmSystemTools::KeyWOW64_32;
-  cmSystemTools::KeyWOW64 other_view = cmSystemTools::KeyWOW64_64;
-  if(this->Makefile->PlatformIs64Bit())
-    {
-    view = cmSystemTools::KeyWOW64_64;
-    other_view = cmSystemTools::KeyWOW64_32;
-    }
-
-  // Expand using the view of the target application.
-  std::string expanded = inPath;
-  cmSystemTools::ExpandRegistryValues(expanded, view);
-  cmSystemTools::GlobDirs(expanded, outPaths);
-
-  // Executables can be either 32-bit or 64-bit, so expand using the
-  // alternative view.
-  if(expanded != inPath && this->CMakePathName == "PROGRAM")
-    {
-    expanded = inPath;
-    cmSystemTools::ExpandRegistryValues(expanded, other_view);
-    cmSystemTools::GlobDirs(expanded, outPaths);
-    }
-}
-
-//----------------------------------------------------------------------------
-void cmFindCommon::AddCMakePath(const std::string& variable,
-                                std::vector<std::string>& outPaths)
-{
-  // 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(tmp, CMakePath, outPaths);
-    }
-}
-
-//----------------------------------------------------------------------------
-void cmFindCommon::AddEnvPath(const char* variable,
-                              std::vector<std::string>& outPaths)
-{
-  // 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(tmp, EnvPath, outPaths);
-}
-
-//----------------------------------------------------------------------------
-void cmFindCommon::AddPathsInternal(std::vector<std::string> const& inPaths,
-                                    PathType pathType,
-                                    std::vector<std::string>& outPaths)
-{
-  for(std::vector<std::string>::const_iterator i = inPaths.begin();
-      i != inPaths.end(); ++i)
-    {
-    this->AddPathInternal(this->MakeFullPath(*i, pathType), outPaths);
-    }
-}
-
-//----------------------------------------------------------------------------
-void cmFindCommon::AddPathInternal(std::string const& inPath,
-                                   std::vector<std::string>& outPaths)
-{
-  if(inPath.empty())
-    {
-    return;
-    }
-
-  // Insert the path if has not already been emitted.
-  if(this->SearchPathsEmitted.insert(inPath).second)
-    {
-    outPaths.push_back(inPath);
-    }
-}
-
 //----------------------------------------------------------------------------
 void AddTrailingSlash(std::string& s)
 {
@@ -458,17 +361,15 @@ void cmFindCommon::ComputeFinalPaths()
   this->GetIgnoredPaths(ignored);
 
   // Combine the seperate path types, filtering out ignores
-  this->SearchPaths.clear();
-  this->FilterPaths(this->CMakeVariablePaths, ignored, this->SearchPaths);
-  this->FilterPaths(this->CMakeEnvironmentPaths, ignored, this->SearchPaths);
-  this->FilterPaths(this->UserHintsPaths, ignored, this->SearchPaths);
-  this->FilterPaths(this->SystemEnvironmentPaths, ignored, this->SearchPaths);
-  this->FilterPaths(this->UserRegistryPaths, ignored, this->SearchPaths);
-  this->FilterPaths(this->BuildPaths, ignored, this->SearchPaths);
-  this->FilterPaths(this->CMakeSystemVariablePaths, ignored,
-                    this->SearchPaths);
-  this->FilterPaths(this->SystemRegistryPaths, ignored, this->SearchPaths);
-  this->FilterPaths(this->UserGuessPaths, ignored, this->SearchPaths);
+  this->CMakeVariablePaths.ExtractWithout(ignored, this->SearchPaths, true);
+  this->CMakeEnvironmentPaths.ExtractWithout(ignored, this->SearchPaths);
+  this->UserHintsPaths.ExtractWithout(ignored, this->SearchPaths);
+  this->SystemEnvironmentPaths.ExtractWithout(ignored, this->SearchPaths);
+  this->UserRegistryPaths.ExtractWithout(ignored, this->SearchPaths);
+  this->BuildPaths.ExtractWithout(ignored, this->SearchPaths);
+  this->CMakeSystemVariablePaths.ExtractWithout(ignored, this->SearchPaths);
+  this->SystemRegistryPaths.ExtractWithout(ignored, this->SearchPaths);
+  this->UserGuessPaths.ExtractWithout(ignored, this->SearchPaths);
 
   // Expand list of paths inside all search roots.
   this->RerootPaths(this->SearchPaths);

+ 18 - 27
Source/cmFindCommon.h

@@ -13,6 +13,7 @@
 #define cmFindCommon_h
 
 #include "cmCommand.h"
+#include "cmSearchPath.h"
 
 /** \class cmFindCommon
  * \brief Base class for FIND_XXX implementations.
@@ -29,15 +30,11 @@ public:
   cmTypeMacro(cmFindCommon, cmCommand);
 
 protected:
+  friend class cmSearchPath;
 
-  enum RootPathMode { RootPathModeBoth,
-                      RootPathModeOnlyRootPath,
-                      RootPathModeNoRootPath };
-
-  enum PathType { FullPath, CMakePath, EnvPath };
-
-  /** Generate a full path based on the particular path type */
-  std::string MakeFullPath(const std::string& path, PathType pathType);
+  enum RootPathMode { RootPathModeNever,
+                      RootPathModeOnly,
+                      RootPathModeBoth };
 
   /** Place a set of search paths under the search roots.  */
   void RerootPaths(std::vector<std::string>& paths);
@@ -60,21 +57,15 @@ protected:
   /** Compute the current default bundle/framework search policy.  */
   void SelectDefaultMacMode();
 
+  // Path arguments prior to path manipulation routines
+  std::vector<std::string> UserHintsArgs;
+  std::vector<std::string> UserGuessArgs;
+
   std::string CMakePathName;
   RootPathMode FindRootPathMode;
 
   bool CheckCommonArgument(std::string const& arg);
   void AddPathSuffix(std::string const& arg);
-  void AddUserPath(std::string const& p,
-                   std::vector<std::string>& outPaths);
-  void AddCMakePath(const std::string& variable,
-                    std::vector<std::string>& outPaths);
-  void AddEnvPath(const char* variable, std::vector<std::string>& outPaths);
-  void AddPathsInternal(std::vector<std::string> const& inPaths,
-                        PathType pathType, std::vector<std::string>& outPaths);
-  void AddPathInternal(std::string const& inPath,
-                       std::vector<std::string>& outPaths);
-
   void SetMakefile(cmMakefile* makefile);
 
   bool NoDefaultPath;
@@ -84,15 +75,15 @@ protected:
   bool NoCMakeSystemPath;
 
   std::vector<std::string> SearchPathSuffixes;
-  std::vector<std::string> CMakeVariablePaths;
-  std::vector<std::string> CMakeEnvironmentPaths;
-  std::vector<std::string> UserHintsPaths;
-  std::vector<std::string> SystemEnvironmentPaths;
-  std::vector<std::string> UserRegistryPaths;
-  std::vector<std::string> BuildPaths;
-  std::vector<std::string> CMakeSystemVariablePaths;
-  std::vector<std::string> SystemRegistryPaths;
-  std::vector<std::string> UserGuessPaths;
+  cmSearchPath CMakeVariablePaths;
+  cmSearchPath CMakeEnvironmentPaths;
+  cmSearchPath UserHintsPaths;
+  cmSearchPath SystemEnvironmentPaths;
+  cmSearchPath UserRegistryPaths;
+  cmSearchPath BuildPaths;
+  cmSearchPath CMakeSystemVariablePaths;
+  cmSearchPath SystemRegistryPaths;
+  cmSearchPath UserGuessPaths;
 
   std::vector<std::string> SearchPaths;
   std::set<std::string> SearchPathsEmitted;

+ 32 - 40
Source/cmFindPackageCommand.cxx

@@ -248,11 +248,11 @@ bool cmFindPackageCommand
       }
     else if(doing == DoingPaths)
       {
-      this->AddUserPath(args[i], this->UserGuessPaths);
+      this->UserGuessArgs.push_back(args[i]);
       }
     else if(doing == DoingHints)
       {
-      this->AddUserPath(args[i], this->UserHintsPaths);
+      this->UserHintsArgs.push_back(args[i]);
       }
     else if(doing == DoingPathSuffixes)
       {
@@ -1153,25 +1153,20 @@ void cmFindPackageCommand::FillPrefixesCMakeEnvironment()
 {
   // 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(MakeFullPath(env, EnvPath),
-                          this->CMakeEnvironmentPaths);
-    }
+  this->CMakeEnvironmentPaths.AddEnvPath(this->Variable);
 
-  this->AddEnvPath("CMAKE_PREFIX_PATH", this->CMakeEnvironmentPaths);
-  this->AddEnvPath("CMAKE_FRAMEWORK_PATH", this->CMakeEnvironmentPaths);
-  this->AddEnvPath("CMAKE_APPBUNDLE_PATH", this->CMakeEnvironmentPaths);
+  // And now the general CMake environment variables
+  this->CMakeEnvironmentPaths.AddEnvPath("CMAKE_PREFIX_PATH");
+  this->CMakeEnvironmentPaths.AddEnvPath("CMAKE_FRAMEWORK_PATH");
+  this->CMakeEnvironmentPaths.AddEnvPath("CMAKE_APPBUNDLE_PATH");
 }
 
 //----------------------------------------------------------------------------
 void cmFindPackageCommand::FillPrefixesCMakeVariable()
 {
-  this->AddCMakePath("CMAKE_PREFIX_PATH", this->CMakeVariablePaths);
-  this->AddCMakePath("CMAKE_FRAMEWORK_PATH", this->CMakeVariablePaths);
-  this->AddCMakePath("CMAKE_APPBUNDLE_PATH", this->CMakeVariablePaths);
+  this->CMakeVariablePaths.AddCMakePath("CMAKE_PREFIX_PATH");
+  this->CMakeVariablePaths.AddCMakePath("CMAKE_FRAMEWORK_PATH");
+  this->CMakeVariablePaths.AddCMakePath("CMAKE_APPBUNDLE_PATH");
 }
 
 //----------------------------------------------------------------------------
@@ -1189,14 +1184,12 @@ void cmFindPackageCommand::FillPrefixesSystemEnvironment()
     if((cmHasLiteralSuffix(*i, "/bin")) ||
        (cmHasLiteralSuffix(*i, "/sbin")))
       {
-      this->AddPathInternal(MakeFullPath(cmSystemTools::GetFilenamePath(*i),
-                                         EnvPath),
-                            this->SystemEnvironmentPaths);
+      this->SystemEnvironmentPaths.AddPath(
+        cmSystemTools::GetFilenamePath(*i));
       }
     else
       {
-      this->AddPathInternal(MakeFullPath(*i, EnvPath),
-                            this->SystemEnvironmentPaths);
+      this->SystemEnvironmentPaths.AddPath(*i);
       }
     }
 }
@@ -1280,7 +1273,7 @@ void cmFindPackageCommand::LoadPackageRegistryWinSystem()
 
 //----------------------------------------------------------------------------
 void cmFindPackageCommand::LoadPackageRegistryWin(bool user, unsigned int view,
-  std::vector<std::string>& outPaths)
+                                                  cmSearchPath& outPaths)
 {
   std::wstring key = L"Software\\Kitware\\CMake\\Packages\\";
   key += cmsys::Encoding::ToWide(this->Name);
@@ -1350,7 +1343,7 @@ public:
 
 //----------------------------------------------------------------------------
 void cmFindPackageCommand::LoadPackageRegistryDir(std::string const& dir,
-  std::vector<std::string>& outPaths)
+                                                  cmSearchPath& outPaths)
 {
   cmsys::Directory files;
   if(!files.Load(dir))
@@ -1388,7 +1381,7 @@ void cmFindPackageCommand::LoadPackageRegistryDir(std::string const& dir,
 
 //----------------------------------------------------------------------------
 bool cmFindPackageCommand::CheckPackageRegistryEntry(const std::string& fname,
-  std::vector<std::string>& outPaths)
+                                                     cmSearchPath& outPaths)
 {
   // Parse the content of one package registry entry.
   if(cmSystemTools::FileIsFullPath(fname.c_str()))
@@ -1400,13 +1393,11 @@ bool cmFindPackageCommand::CheckPackageRegistryEntry(const std::string& fname,
       // The path exists.  Look for the package here.
       if(!cmSystemTools::FileIsDirectory(fname))
         {
-        this->AddPathInternal(
-          MakeFullPath(cmSystemTools::GetFilenamePath(fname), FullPath),
-          outPaths);
+        outPaths.AddPath(cmSystemTools::GetFilenamePath(fname));
         }
       else
         {
-        this->AddPathInternal(MakeFullPath(fname, FullPath), outPaths);
+        outPaths.AddPath(fname);
         }
       return true;
       }
@@ -1443,7 +1434,7 @@ void cmFindPackageCommand::FillPrefixesBuilds()
     if(cmSystemTools::FileIsFullPath(f.c_str()) &&
        cmSystemTools::FileIsDirectory(f.c_str()))
       {
-      this->AddPathInternal(MakeFullPath(f, FullPath), this->BuildPaths);
+      this->BuildPaths.AddPath(f);
       }
     }
 }
@@ -1451,28 +1442,29 @@ void cmFindPackageCommand::FillPrefixesBuilds()
 //----------------------------------------------------------------------------
 void cmFindPackageCommand::FillPrefixesCMakeSystemVariable()
 {
-  this->AddCMakePath("CMAKE_SYSTEM_PREFIX_PATH",
-                     this->CMakeSystemVariablePaths);
-  this->AddCMakePath("CMAKE_SYSTEM_FRAMEWORK_PATH",
-                     this->CMakeSystemVariablePaths);
-  this->AddCMakePath("CMAKE_SYSTEM_APPBUNDLE_PATH",
-                     this->CMakeSystemVariablePaths);
+  this->CMakeSystemVariablePaths.AddCMakePath("CMAKE_SYSTEM_PREFIX_PATH");
+  this->CMakeSystemVariablePaths.AddCMakePath("CMAKE_SYSTEM_FRAMEWORK_PATH");
+  this->CMakeSystemVariablePaths.AddCMakePath("CMAKE_SYSTEM_APPBUNDLE_PATH");
 }
 
 //----------------------------------------------------------------------------
 void cmFindPackageCommand::FillPrefixesUserGuess()
 {
-  std::vector<std::string> inPaths;
-  inPaths.swap(this->UserGuessPaths);
-  this->AddPathsInternal(inPaths, CMakePath, this->UserGuessPaths);
+  for(std::vector<std::string>::const_iterator p = this->UserGuessArgs.begin();
+      p != this->UserGuessArgs.end(); ++p)
+    {
+    this->UserGuessPaths.AddUserPath(*p);
+    }
 }
 
 //----------------------------------------------------------------------------
 void cmFindPackageCommand::FillPrefixesUserHints()
 {
-  std::vector<std::string> inPaths;
-  inPaths.swap(this->UserHintsPaths);
-  this->AddPathsInternal(inPaths, CMakePath, this->UserHintsPaths);
+  for(std::vector<std::string>::const_iterator p = this->UserHintsArgs.begin();
+      p != this->UserHintsArgs.end(); ++p)
+    {
+    this->UserHintsPaths.AddUserPath(*p);
+    }
 }
 
 //----------------------------------------------------------------------------

+ 3 - 4
Source/cmFindPackageCommand.h

@@ -78,14 +78,13 @@ private:
   void FillPrefixesCMakeSystemVariable();
   void FillPrefixesUserGuess();
   void FillPrefixesUserHints();
-  void LoadPackageRegistryDir(std::string const& dir,
-                              std::vector<std::string>& outPaths);
+  void LoadPackageRegistryDir(std::string const& dir, cmSearchPath& outPaths);
   void LoadPackageRegistryWinUser();
   void LoadPackageRegistryWinSystem();
   void LoadPackageRegistryWin(bool user, unsigned int view,
-                              std::vector<std::string>& outPaths);
+                              cmSearchPath& outPaths);
   bool CheckPackageRegistryEntry(const std::string& fname,
-                                 std::vector<std::string>& outPaths);
+                                 cmSearchPath& outPaths);
   bool SearchDirectory(std::string const& dir);
   bool CheckDirectory(std::string const& dir);
   bool FindConfigFile(std::string const& dir, std::string& file);

+ 243 - 0
Source/cmSearchPath.cxx

@@ -0,0 +1,243 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+
+#include "cmSearchPath.h"
+#include "cmFindCommon.h"
+
+//----------------------------------------------------------------------------
+cmSearchPath::cmSearchPath(cmFindCommon* findCmd,
+                           const std::string& groupLabel)
+: FindName(findCmd->CMakePathName), Makefile(findCmd->Makefile),
+  Emitted(findCmd->SearchPathsEmitted), Label(groupLabel)
+{
+}
+
+//----------------------------------------------------------------------------
+cmSearchPath::~cmSearchPath()
+{
+}
+
+//----------------------------------------------------------------------------
+
+void cmSearchPath::ExtractWithout(const std::set<std::string>& ignore,
+                                  std::vector<std::string>& outPaths,
+                                  bool clear) const
+{
+  if(clear)
+    {
+    outPaths.clear();
+    }
+  for(std::vector<std::string>::const_iterator p = this->Paths.begin();
+      p != this->Paths.end(); ++p)
+    {
+    if(ignore.count(*p) == 0)
+      {
+      outPaths.push_back(*p);
+      }
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmSearchPath::AddPath(const std::string& path)
+{
+  this->AddPathInternal(path);
+}
+
+//----------------------------------------------------------------------------
+void cmSearchPath::AddUserPath(const std::string& path)
+{
+  std::vector<std::string> outPaths;
+
+  // We should view the registry as the target application would view
+  // it.
+  cmSystemTools::KeyWOW64 view = cmSystemTools::KeyWOW64_32;
+  cmSystemTools::KeyWOW64 other_view = cmSystemTools::KeyWOW64_64;
+  if(this->Makefile->PlatformIs64Bit())
+    {
+    view = cmSystemTools::KeyWOW64_64;
+    other_view = cmSystemTools::KeyWOW64_32;
+    }
+
+  // Expand using the view of the target application.
+  std::string expanded = path;
+  cmSystemTools::ExpandRegistryValues(expanded, view);
+  cmSystemTools::GlobDirs(expanded, outPaths);
+
+  // Executables can be either 32-bit or 64-bit, so expand using the
+  // alternative view.
+  if(expanded != path && this->FindName == "PROGRAM")
+    {
+    expanded = path;
+    cmSystemTools::ExpandRegistryValues(expanded, other_view);
+    cmSystemTools::GlobDirs(expanded, outPaths);
+    }
+
+  // Process them all from the current directory
+  for(std::vector<std::string>::const_iterator p = outPaths.begin();
+      p != outPaths.end(); ++p)
+    {
+    this->AddPathInternal(*p, this->Makefile->GetCurrentDirectory());
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmSearchPath::AddCMakePath(const std::string& variable)
+{
+  // Get a path from a CMake variable.
+  if(const char* value = this->Makefile->GetDefinition(variable))
+    {
+    std::vector<std::string> expanded;
+    cmSystemTools::ExpandListArgument(value, expanded);
+
+    for(std::vector<std::string>::const_iterator p = expanded.begin();
+        p!= expanded.end(); ++p)
+      {
+      this->AddPathInternal(*p, this->Makefile->GetCurrentDirectory());
+      }
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmSearchPath::AddEnvPath(const std::string& variable)
+{
+  std::vector<std::string> expanded;
+  cmSystemTools::GetPath(expanded, variable.c_str());
+  for(std::vector<std::string>::const_iterator p = expanded.begin();
+      p!= expanded.end(); ++p)
+    {
+    this->AddPathInternal(*p);
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmSearchPath::AddCMakePrefixPath(const std::string& variable)
+{
+  // Get a path from a CMake variable.
+  if(const char* value = this->Makefile->GetDefinition(variable))
+    {
+    std::vector<std::string> expanded;
+    cmSystemTools::ExpandListArgument(value, expanded);
+
+    this->AddPrefixPaths(expanded, this->Makefile->GetCurrentDirectory());
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmSearchPath::AddEnvPrefixPath(const std::string& variable)
+{
+  std::vector<std::string> expanded;
+  cmSystemTools::GetPath(expanded, variable.c_str());
+  this->AddPrefixPaths(expanded);
+}
+
+//----------------------------------------------------------------------------
+void cmSearchPath::AddSuffixes(const std::vector<std::string>& suffixes)
+{
+  std::vector<std::string> inPaths;
+  inPaths.swap(this->Paths);
+  this->Paths.reserve(inPaths.size()*(suffixes.size()+1));
+
+  for(std::vector<std::string>::iterator ip = inPaths.begin();
+      ip != inPaths.end(); ++ip)
+    {
+    cmSystemTools::ConvertToUnixSlashes(*ip);
+
+    // if *i is only / then do not add a //
+    // this will get incorrectly considered a network
+    // path on windows and cause huge delays.
+    std::string p = *ip;
+    if(!p.empty() && *p.rbegin() != '/')
+      {
+      p += "/";
+      }
+
+    // Combine with all the suffixes
+    for(std::vector<std::string>::const_iterator s = suffixes.begin();
+        s != suffixes.end(); ++s)
+      {
+      this->Paths.push_back(p+*s);
+      }
+
+    // And now the original w/o any suffix
+    this->Paths.push_back(*ip);
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths,
+                                  const char *base)
+{
+  // default for programs
+  std::string subdir = "bin";
+
+  if (this->FindName == "INCLUDE")
+    {
+    subdir = "include";
+    }
+  else if (this->FindName == "LIBRARY")
+    {
+    subdir = "lib";
+    }
+  else if (this->FindName == "FRAMEWORK")
+    {
+    subdir = "";  // ? what to do for frameworks ?
+    }
+
+  for(std::vector<std::string>::const_iterator p = paths.begin();
+      p != paths.end(); ++p)
+    {
+    std::string dir = *p;
+    if(!subdir.empty() && !dir.empty() && *dir.rbegin() != '/')
+      {
+      dir += "/";
+      }
+    if(subdir == "include" || subdir == "lib")
+      {
+      const char* arch =
+        this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE");
+      if(arch && *arch)
+        {
+        this->AddPathInternal(dir+subdir+"/"+arch, base);
+        }
+      }
+    std::string add = dir + subdir;
+    if(add != "/")
+      {
+      this->AddPathInternal(add, base);
+      }
+    if (subdir == "bin")
+      {
+      this->AddPathInternal(dir+"sbin", base);
+      }
+    if(!subdir.empty() && *p != "/")
+      {
+      this->AddPathInternal(*p, base);
+      }
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmSearchPath::AddPathInternal(const std::string& path, const char *base)
+{
+  std::string collapsed = cmSystemTools::CollapseFullPath(path, base);
+
+   if(collapsed.empty())
+    {
+    return;
+    }
+
+  // Insert the path if has not already been emitted.
+  if(this->Emitted.insert(collapsed).second)
+    {
+    this->Paths.push_back(collapsed);
+    }
+}

+ 60 - 0
Source/cmSearchPath.h

@@ -0,0 +1,60 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#ifndef cmSearchPath_h
+#define cmSearchPath_h
+
+#include "cmStandardIncludes.h"
+
+class cmFindCommon;
+
+/** \class cmSearchPath
+ * \brief Base class for FIND_XXX implementations.
+ *
+ * cmSearchPath is a container that encapsulates search path construction and
+ * management
+ */
+class cmSearchPath
+{
+public:
+  cmSearchPath(cmFindCommon* findCmd, const std::string& groupLabel);
+  ~cmSearchPath();
+
+  const std::string& GetLabel() const { return this->Label; }
+  const std::vector<std::string>& GetPaths() const { return this->Paths; }
+
+  void ExtractWithout(const std::set<std::string>& ignore,
+                      std::vector<std::string>& outPaths,
+                      bool clear = false) const;
+
+  void AddPath(const std::string& path);
+  void AddUserPath(const std::string& path);
+  void AddCMakePath(const std::string& variable);
+  void AddEnvPath(const std::string& variable);
+  void AddCMakePrefixPath(const std::string& variable);
+  void AddEnvPrefixPath(const std::string& variable);
+  void AddSuffixes(const std::vector<std::string>& suffixes);
+
+protected:
+  void AddPrefixPaths(const std::vector<std::string>& paths,
+                      const char *base = 0);
+  void AddPathInternal(const std::string& path, const char *base = 0);
+
+  // Members collected from the calling find command
+  const std::string& FindName;
+  cmMakefile* const& Makefile;
+  std::set<std::string>& Emitted;
+
+  std::string Label;
+  std::vector<std::string> Paths;
+};
+
+#endif