[Cmake-commits] [cmake-commits] king committed cmFindPackageCommand.cxx 1.60 1.61 cmFindPackageCommand.h 1.28 1.29

cmake-commits at cmake.org cmake-commits at cmake.org
Tue Sep 1 14:04:31 EDT 2009


Update of /cvsroot/CMake/CMake/Source
In directory public:/mounts/ram/cvs-serv26918/Source

Modified Files:
	cmFindPackageCommand.cxx cmFindPackageCommand.h 
Log Message:
Teach find_package to search a "package registry"

A common user workflow is to build a series of dependent projects in
order.  Each project locates its dependencies with find_package.  We
introduce a "user package registry" to help find_package locate packages
built in non-standard search locations.

The registry explicitly stores locations of build trees providing
instances of a given package.  There is no defined order among the
locations specified.  These locations should provide package
configuration files (<package>-config.cmake) and package version files
(<package>-config-version.cmake) so that find_package will recognize the
packages and test version numbers.


Index: cmFindPackageCommand.h
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmFindPackageCommand.h,v
retrieving revision 1.28
retrieving revision 1.29
diff -C 2 -d -r1.28 -r1.29
*** cmFindPackageCommand.h	22 Jan 2009 18:18:39 -0000	1.28
--- cmFindPackageCommand.h	1 Sep 2009 18:04:27 -0000	1.29
***************
*** 91,94 ****
--- 91,95 ----
    void AddPrefixesCMakeVariable();
    void AddPrefixesSystemEnvironment();
+   void AddPrefixesRegistry();
    void AddPrefixesBuilds();
    void AddPrefixesCMakeSystemVariable();
***************
*** 96,99 ****
--- 97,103 ----
    void AddPrefixesUserHints();
    void ComputeFinalPrefixes();
+   void LoadPackageRegistryDir(std::string const& dir);
+   void LoadPackageRegistryWin();
+   bool CheckPackageRegistryEntry(std::istream& is);
    bool SearchDirectory(std::string const& dir);
    bool CheckDirectory(std::string const& dir);
***************
*** 131,134 ****
--- 135,139 ----
    bool Compatibility_1_6;
    bool NoModule;
+   bool NoRegistry;
    bool NoBuilds;
    bool DebugMode;

Index: cmFindPackageCommand.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmFindPackageCommand.cxx,v
retrieving revision 1.60
retrieving revision 1.61
diff -C 2 -d -r1.60 -r1.61
*** cmFindPackageCommand.cxx	5 Aug 2009 13:56:02 -0000	1.60
--- cmFindPackageCommand.cxx	1 Sep 2009 18:04:27 -0000	1.61
***************
*** 16,19 ****
--- 16,21 ----
  =========================================================================*/
  #include "cmFindPackageCommand.h"
+ 
+ #include <cmsys/Directory.hxx>
  #include <cmsys/RegularExpression.hxx>
  
***************
*** 61,64 ****
--- 63,67 ----
    this->Quiet = false;
    this->Required = false;
+   this->NoRegistry = false;
    this->NoBuilds = false;
    this->NoModule = false;
***************
*** 129,132 ****
--- 132,136 ----
      "               [NO_CMAKE_PATH]\n"
      "               [NO_SYSTEM_ENVIRONMENT_PATH]\n"
+     "               [NO_CMAKE_PACKAGE_REGISTRY]\n"
      "               [NO_CMAKE_BUILDS_PATH]\n"
      "               [NO_CMAKE_SYSTEM_PATH]\n"
***************
*** 282,286 ****
      "It is intended for the case when a user is building multiple "
      "dependent projects one after another.\n"
!     "6. Search cmake variables defined in the Platform files "
      "for the current system.  This can be skipped if NO_CMAKE_SYSTEM_PATH "
      "is passed.\n"
--- 286,296 ----
      "It is intended for the case when a user is building multiple "
      "dependent projects one after another.\n"
!     "6. Search paths stored in the CMake user package registry.  "
!     "This can be skipped if NO_CMAKE_PACKAGE_REGISTRY is passed.  "
!     "Paths are stored in the registry when CMake configures a project "
!     "that invokes export(PACKAGE <name>).  "
!     "See the export(PACKAGE) command documentation for more details."
!     "\n"
!     "7. Search cmake variables defined in the Platform files "
      "for the current system.  This can be skipped if NO_CMAKE_SYSTEM_PATH "
      "is passed.\n"
***************
*** 288,292 ****
      "   CMAKE_SYSTEM_FRAMEWORK_PATH\n"
      "   CMAKE_SYSTEM_APPBUNDLE_PATH\n"
!     "7. Search paths specified by the PATHS option.  "
      "These are typically hard-coded guesses.\n"
      ;
--- 298,302 ----
      "   CMAKE_SYSTEM_FRAMEWORK_PATH\n"
      "   CMAKE_SYSTEM_APPBUNDLE_PATH\n"
!     "8. Search paths specified by the PATHS option.  "
      "These are typically hard-coded guesses.\n"
      ;
***************
*** 421,424 ****
--- 431,441 ----
        doing = DoingNone;
        }
+     else if(args[i] == "NO_CMAKE_PACKAGE_REGISTRY")
+       {
+       this->NoRegistry = true;
+       this->NoModule = true;
+       this->Compatibility_1_6 = false;
+       doing = DoingNone;
+       }
      else if(args[i] == "NO_CMAKE_BUILDS_PATH")
        {
***************
*** 1066,1069 ****
--- 1083,1087 ----
    this->AddPrefixesUserHints();
    this->AddPrefixesSystemEnvironment();
+   this->AddPrefixesRegistry();
    this->AddPrefixesBuilds();
    this->AddPrefixesCMakeSystemVariable();
***************
*** 1133,1136 ****
--- 1151,1320 ----
  
  //----------------------------------------------------------------------------
+ void cmFindPackageCommand::AddPrefixesRegistry()
+ {
+   if(this->NoRegistry || this->NoDefaultPath)
+     {
+     return;
+     }
+ 
+ #if defined(_WIN32) && !defined(__CYGWIN__)
+   this->LoadPackageRegistryWin();
+ #else
+   if(const char* home = cmSystemTools::GetEnv("HOME"))
+     {
+     std::string dir = home;
+     dir += "/.cmake/packages/";
+     dir += this->Name;
+     this->LoadPackageRegistryDir(dir);
+     }
+ #endif
+ }
+ 
+ #if defined(_WIN32) && !defined(__CYGWIN__)
+ # include <windows.h>
+ # undef GetCurrentDirectory
+ //----------------------------------------------------------------------------
+ void cmFindPackageCommand::LoadPackageRegistryWin()
+ {
+   std::string key = "Software\\Kitware\\CMake\\Packages\\";
+   key += this->Name;
+   std::set<cmStdString> bad;
+   HKEY hKey;
+   if(RegOpenKeyEx(HKEY_CURRENT_USER, key.c_str(),
+                   0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
+     {
+     DWORD valueType = REG_NONE;
+     char name[16384];
+     std::vector<char> data(512);
+     bool done = false;
+     DWORD index = 0;
+     while(!done)
+       {
+       DWORD nameSize = static_cast<DWORD>(sizeof(name));
+       DWORD dataSize = static_cast<DWORD>(data.size()-1);
+       switch(RegEnumValue(hKey, index, name, &nameSize,
+                           0, &valueType, (BYTE*)&data[0], &dataSize))
+         {
+         case ERROR_SUCCESS:
+           ++index;
+           if(valueType == REG_SZ)
+             {
+             data[dataSize] = 0;
+             cmsys_ios::stringstream ss(&data[0]);
+             if(this->CheckPackageRegistryEntry(ss))
+               {
+               // The entry is okay.
+               continue;
+               }
+             }
+           bad.insert(name);
+           break;
+         case ERROR_MORE_DATA:
+           data.resize(dataSize+1);
+           break;
+         case ERROR_NO_MORE_ITEMS: default: done = true; break;
+         }
+       }
+     RegCloseKey(hKey);
+     }
+ 
+   // Remove bad values if possible.
+   if(!bad.empty() &&
+      RegOpenKeyEx(HKEY_CURRENT_USER, key.c_str(),
+                   0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS)
+     {
+     for(std::set<cmStdString>::const_iterator vi = bad.begin();
+         vi != bad.end(); ++vi)
+       {
+       RegDeleteValue(hKey, vi->c_str());
+       }
+     RegCloseKey(hKey);
+     }
+ }
+ #else
+ //----------------------------------------------------------------------------
+ class cmFindPackageCommandHoldFile
+ {
+   const char* File;
+ public:
+   cmFindPackageCommandHoldFile(const char* f): File(f) {}
+   ~cmFindPackageCommandHoldFile()
+     { if(this->File) { cmSystemTools::RemoveFile(this->File); } }
+   void Release() { this->File = 0; }
+ };
+ 
+ //----------------------------------------------------------------------------
+ void cmFindPackageCommand::LoadPackageRegistryDir(std::string const& dir)
+ {
+   cmsys::Directory files;
+   if(!files.Load(dir.c_str()))
+     {
+     return;
+     }
+ 
+   std::string fname;
+   for(unsigned long i=0; i < files.GetNumberOfFiles(); ++i)
+     {
+     fname = dir;
+     fname += "/";
+     fname += files.GetFile(i);
+ 
+     if(!cmSystemTools::FileIsDirectory(fname.c_str()))
+       {
+       // Hold this file hostage until it behaves.
+       cmFindPackageCommandHoldFile holdFile(fname.c_str());
+ 
+       // Load the file.
+       std::ifstream fin(fname.c_str(), std::ios::in | cmsys_ios_binary);
+       if(fin && this->CheckPackageRegistryEntry(fin))
+         {
+         // The file references an existing package, so release it.
+         holdFile.Release();
+         }
+       }
+     }
+ 
+   // TODO: Wipe out the directory if it is empty.
+ }
+ #endif
+ 
+ //----------------------------------------------------------------------------
+ bool cmFindPackageCommand::CheckPackageRegistryEntry(std::istream& is)
+ {
+   // Parse the content of one package registry entry.
+   std::string fname;
+   if(cmSystemTools::GetLineFromStream(is, fname) &&
+      cmSystemTools::FileIsFullPath(fname.c_str()))
+     {
+     // The first line in the stream is the full path to a file or
+     // directory containing the package.
+     if(cmSystemTools::FileExists(fname.c_str()))
+       {
+       // The path exists.  Look for the package here.
+       if(!cmSystemTools::FileIsDirectory(fname.c_str()))
+         {
+         fname = cmSystemTools::GetFilenamePath(fname);
+         }
+       this->AddPathInternal(fname, FullPath);
+       return true;
+       }
+     else
+       {
+       // The path does not exist.  Assume the stream content is
+       // associated with an old package that no longer exists, and
+       // delete it to keep the package registry clean.
+       return false;
+       }
+     }
+   else
+     {
+     // The first line in the stream is not the full path to a file or
+     // directory.  Assume the stream content was created by a future
+     // version of CMake that uses a different format, and leave it.
+     return true;
+     }
+ }
+ 
+ //----------------------------------------------------------------------------
  void cmFindPackageCommand::AddPrefixesBuilds()
  {
***************
*** 1397,1401 ****
  
  //----------------------------------------------------------------------------
- #include <cmsys/Directory.hxx>
  #include <cmsys/Glob.hxx>
  #include <cmsys/String.h>
--- 1581,1584 ----



More information about the Cmake-commits mailing list