Browse Source

Merge topic 'find_package-system-registry'

08b9397 find_package: Fix system package registry test path conversion
93021ad find_package: Test system package registry when possible
b95f3ca find_package: Check both 32-bit and 64-bit registry views
a0d76c1 find_package: Search a "system package registry"
549458f find_package: Document user package registry locations
c9563db find_package: Cleanup user package registry less aggressively
4df1197 find_package: Rename implementation of user package registry
Brad King 14 years ago
parent
commit
19a4b8856d

+ 88 - 27
Source/cmFindPackageCommand.cxx

@@ -54,7 +54,8 @@ cmFindPackageCommand::cmFindPackageCommand()
   this->CMakePathName = "PACKAGE";
   this->Quiet = false;
   this->Required = false;
-  this->NoRegistry = false;
+  this->NoUserRegistry = false;
+  this->NoSystemRegistry = false;
   this->NoBuilds = false;
   this->NoModule = false;
   this->DebugMode = false;
@@ -140,6 +141,7 @@ void cmFindPackageCommand::GenerateDocumentation()
     "               [NO_CMAKE_PACKAGE_REGISTRY]\n"
     "               [NO_CMAKE_BUILDS_PATH]\n"
     "               [NO_CMAKE_SYSTEM_PATH]\n"
+    "               [NO_CMAKE_SYSTEM_PACKAGE_REGISTRY]\n"
     "               [CMAKE_FIND_ROOT_PATH_BOTH |\n"
     "                ONLY_CMAKE_FIND_ROOT_PATH |\n"
     "                NO_CMAKE_FIND_ROOT_PATH])\n"
@@ -299,9 +301,16 @@ void cmFindPackageCommand::GenerateDocumentation()
     "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."
+    "On Windows a <package> may appear under registry key\n"
+    "  HKEY_CURRENT_USER\\Software\\Kitware\\CMake\\Packages\\<package>\n"
+    "as a REG_SZ value, with arbitrary name, that specifies the directory "
+    "containing the package configuration file.  "
+    "On UNIX platforms a <package> may appear under the directory\n"
+    "  ~/.cmake/packages/<package>\n"
+    "as a file, with arbitrary name, whose content specifies the directory "
+    "containing the package configuration file.  "
+    "See the export(PACKAGE) command to create user package registry entries "
+    "for project build trees."
     "\n"
     "7. Search cmake variables defined in the Platform files "
     "for the current system.  This can be skipped if NO_CMAKE_SYSTEM_PATH "
@@ -309,7 +318,15 @@ void cmFindPackageCommand::GenerateDocumentation()
     "   CMAKE_SYSTEM_PREFIX_PATH\n"
     "   CMAKE_SYSTEM_FRAMEWORK_PATH\n"
     "   CMAKE_SYSTEM_APPBUNDLE_PATH\n"
-    "8. Search paths specified by the PATHS option.  "
+    "8. Search paths stored in the CMake system package registry.  "
+    "This can be skipped if NO_CMAKE_SYSTEM_PACKAGE_REGISTRY is passed.  "
+    "On Windows a <package> may appear under registry key\n"
+    "  HKEY_LOCAL_MACHINE\\Software\\Kitware\\CMake\\Packages\\<package>\n"
+    "as a REG_SZ value, with arbitrary name, that specifies the directory "
+    "containing the package configuration file.  "
+    "There is no system package registry on non-Windows platforms."
+    "\n"
+    "9. Search paths specified by the PATHS option.  "
     "These are typically hard-coded guesses.\n"
     ;
   this->CommandDocumentation += this->GenericDocumentationMacPolicy;
@@ -444,7 +461,14 @@ bool cmFindPackageCommand
       }
     else if(args[i] == "NO_CMAKE_PACKAGE_REGISTRY")
       {
-      this->NoRegistry = true;
+      this->NoUserRegistry = true;
+      this->NoModule = true;
+      this->Compatibility_1_6 = false;
+      doing = DoingNone;
+      }
+    else if(args[i] == "NO_CMAKE_SYSTEM_PACKAGE_REGISTRY")
+      {
+      this->NoSystemRegistry = true;
       this->NoModule = true;
       this->Compatibility_1_6 = false;
       doing = DoingNone;
@@ -1181,9 +1205,10 @@ void cmFindPackageCommand::ComputePrefixes()
   this->AddPrefixesCMakeEnvironment();
   this->AddPrefixesUserHints();
   this->AddPrefixesSystemEnvironment();
-  this->AddPrefixesRegistry();
+  this->AddPrefixesUserRegistry();
   this->AddPrefixesBuilds();
   this->AddPrefixesCMakeSystemVariable();
+  this->AddPrefixesSystemRegistry();
   this->AddPrefixesUserGuess();
   this->ComputeFinalPrefixes();
 }
@@ -1249,15 +1274,15 @@ void cmFindPackageCommand::AddPrefixesSystemEnvironment()
 }
 
 //----------------------------------------------------------------------------
-void cmFindPackageCommand::AddPrefixesRegistry()
+void cmFindPackageCommand::AddPrefixesUserRegistry()
 {
-  if(this->NoRegistry || this->NoDefaultPath)
+  if(this->NoUserRegistry || this->NoDefaultPath)
     {
     return;
     }
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
-  this->LoadPackageRegistryWin();
+  this->LoadPackageRegistryWinUser();
 #elif defined(__HAIKU__)
   BPath dir;
   if (find_directory(B_USER_SETTINGS_DIRECTORY, &dir) == B_OK)
@@ -1277,18 +1302,63 @@ void cmFindPackageCommand::AddPrefixesRegistry()
 #endif
 }
 
+//----------------------------------------------------------------------------
+void cmFindPackageCommand::AddPrefixesSystemRegistry()
+{
+  if(this->NoSystemRegistry || this->NoDefaultPath)
+    {
+    return;
+    }
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  this->LoadPackageRegistryWinSystem();
+#endif
+}
+
 #if defined(_WIN32) && !defined(__CYGWIN__)
 # include <windows.h>
 # undef GetCurrentDirectory
+  // http://msdn.microsoft.com/en-us/library/aa384253%28v=vs.85%29.aspx
+# if !defined(KEY_WOW64_32KEY)
+#  define KEY_WOW64_32KEY 0x0200
+# endif
+# if !defined(KEY_WOW64_64KEY)
+#  define KEY_WOW64_64KEY 0x0100
+# endif
+//----------------------------------------------------------------------------
+void cmFindPackageCommand::LoadPackageRegistryWinUser()
+{
+  // HKEY_CURRENT_USER\\Software shares 32-bit and 64-bit views.
+  this->LoadPackageRegistryWin(true, 0);
+}
+
 //----------------------------------------------------------------------------
-void cmFindPackageCommand::LoadPackageRegistryWin()
+void cmFindPackageCommand::LoadPackageRegistryWinSystem()
+{
+  // HKEY_LOCAL_MACHINE\\SOFTWARE has separate 32-bit and 64-bit views.
+  // Prefer the target platform view first.
+  if(this->Makefile->PlatformIs64Bit())
+    {
+    this->LoadPackageRegistryWin(false, KEY_WOW64_64KEY);
+    this->LoadPackageRegistryWin(false, KEY_WOW64_32KEY);
+    }
+  else
+    {
+    this->LoadPackageRegistryWin(false, KEY_WOW64_32KEY);
+    this->LoadPackageRegistryWin(false, KEY_WOW64_64KEY);
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmFindPackageCommand::LoadPackageRegistryWin(bool user,
+                                                  unsigned int view)
 {
   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)
+  if(RegOpenKeyEx(user? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, key.c_str(),
+                  0, KEY_QUERY_VALUE|view, &hKey) == ERROR_SUCCESS)
     {
     DWORD valueType = REG_NONE;
     char name[16384];
@@ -1308,13 +1378,12 @@ void cmFindPackageCommand::LoadPackageRegistryWin()
             {
             data[dataSize] = 0;
             cmsys_ios::stringstream ss(&data[0]);
-            if(this->CheckPackageRegistryEntry(ss))
+            if(!this->CheckPackageRegistryEntry(ss))
               {
-              // The entry is okay.
-              continue;
+              // The entry is invalid.
+              bad.insert(name);
               }
             }
-          bad.insert(name);
           break;
         case ERROR_MORE_DATA:
           data.resize(dataSize+1);
@@ -1326,9 +1395,9 @@ void cmFindPackageCommand::LoadPackageRegistryWin()
     }
 
   // Remove bad values if possible.
-  if(!bad.empty() &&
+  if(user && !bad.empty() &&
      RegOpenKeyEx(HKEY_CURRENT_USER, key.c_str(),
-                  0, KEY_SET_VALUE, &hKey) == ERROR_SUCCESS)
+                  0, KEY_SET_VALUE|view, &hKey) == ERROR_SUCCESS)
     {
     for(std::set<cmStdString>::const_iterator vi = bad.begin();
         vi != bad.end(); ++vi)
@@ -2286,11 +2355,3 @@ bool cmFindPackageCommand::SearchAppBundlePrefix(std::string const& prefix_in)
 }
 
 // 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]

+ 7 - 3
Source/cmFindPackageCommand.h

@@ -87,14 +87,17 @@ private:
   void AddPrefixesCMakeEnvironment();
   void AddPrefixesCMakeVariable();
   void AddPrefixesSystemEnvironment();
-  void AddPrefixesRegistry();
+  void AddPrefixesUserRegistry();
+  void AddPrefixesSystemRegistry();
   void AddPrefixesBuilds();
   void AddPrefixesCMakeSystemVariable();
   void AddPrefixesUserGuess();
   void AddPrefixesUserHints();
   void ComputeFinalPrefixes();
   void LoadPackageRegistryDir(std::string const& dir);
-  void LoadPackageRegistryWin();
+  void LoadPackageRegistryWinUser();
+  void LoadPackageRegistryWinSystem();
+  void LoadPackageRegistryWin(bool user, unsigned int view);
   bool CheckPackageRegistryEntry(std::istream& is);
   bool SearchDirectory(std::string const& dir);
   bool CheckDirectory(std::string const& dir);
@@ -132,7 +135,8 @@ private:
   bool Required;
   bool Compatibility_1_6;
   bool NoModule;
-  bool NoRegistry;
+  bool NoUserRegistry;
+  bool NoSystemRegistry;
   bool NoBuilds;
   bool DebugMode;
   bool UseLib64Paths;

+ 41 - 0
Tests/FindPackageTest/CMakeLists.txt

@@ -37,6 +37,38 @@ FIND_PACKAGE(VersionTestB 1.2)
 FIND_PACKAGE(VersionTestC 1.2.3)
 FIND_PACKAGE(VersionTestD 1.2.3.4)
 
+#-----------------------------------------------------------------------------
+# Test system package registry if possible.
+SET(CMakeTestSystemPackage "")
+IF(WIN32 AND NOT CYGWIN)
+  # Try writing a value to the system package registry.
+  SET(_data "${FindPackageTest_SOURCE_DIR}/SystemPackage")
+  SET(_key "HKLM\\Software\\Kitware\\CMake\\Packages\\CMakeTestSystemPackage")
+  SET(_file "${FindPackageTest_BINARY_DIR}/CMakeTestSystemPackage.data")
+  FILE(WRITE ${_file} "${_data}\n")
+  EXECUTE_PROCESS(
+    COMMAND ${CMAKE_COMMAND} -E md5sum ${_file}
+    OUTPUT_VARIABLE _output ERROR_VARIABLE _error RESULT_VARIABLE _failed
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+    )
+  STRING(REGEX REPLACE " .*" "" _value "${_output}")
+  IF(NOT _failed AND _value)
+    EXECUTE_PROCESS(
+      COMMAND reg add "${_key}" /v "${_value}" /t REG_SZ /d "${_data}" /f
+      OUTPUT_VARIABLE _output ERROR_VARIABLE _output RESULT_VARIABLE _failed
+      )
+  ENDIF()
+  # If the above worked, add the rest of the test and a rule to
+  # cleanup the value.
+  IF(NOT _failed)
+    MESSAGE(STATUS "HKLM is writable: enabling CMakeTestSystemPackage")
+    SET(CMakeTestSystemPackage_CLEANUP reg delete "${_key}" /v "${_value}" /f)
+    SET(CMakeTestSystemPackage CMakeTestSystemPackage)
+  ELSE()
+    MESSAGE(STATUS "HKLM is readonly: disabling CMakeTestSystemPackage")
+  ENDIF()
+ENDIF()
+
 #-----------------------------------------------------------------------------
 
 #SET(CMAKE_FIND_DEBUG_MODE 1)
@@ -49,6 +81,7 @@ SET(PACKAGES
   wibbleA wibbleB
   RecursiveA RecursiveB RecursiveC
   EnvA EnvB
+  ${CMakeTestSystemPackage}
   )
 FOREACH(p ${PACKAGES})
   SET(${p}_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
@@ -116,6 +149,13 @@ SET(ENV{EnvA_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/lib/zot-3.1")
 FIND_PACKAGE(EnvA 3.1 EXACT QUIET NAMES zot) # Should Work
 FIND_PACKAGE(EnvB 3.1 EXACT QUIET NAMES zot) # Should Fail
 
+# Test system package registry if available.
+IF(CMakeTestSystemPackage)
+  FIND_PACKAGE(CMakeTestSystemPackage)
+  EXECUTE_PROCESS(COMMAND ${CMakeTestSystemPackage_CLEANUP}
+    OUTPUT_VARIABLE _output ERROR_VARIABLE _error)
+ENDIF()
+
 # Expected locations at which packages should be found.
 SET(foo_EXPECTED "lib/foo-1.2/foo-config.cmake")
 SET(Foo_EXPECTED "lib/foo-1.2/CMake/FooConfig.cmake")
@@ -145,6 +185,7 @@ SET(RecursiveB_EXPECTED "lib/zot-2.0/zot-config.cmake")
 SET(RecursiveC_EXPECTED "lib/zot-3.1/zot-config.cmake")
 SET(EnvA_EXPECTED "lib/zot-3.1/zot-config.cmake")
 SET(EnvB_MISSING "EnvB_DIR-NOTFOUND")
+SET(CMakeTestSystemPackage_EXPECTED "SystemPackage/CMakeTestSystemPackageConfig.cmake")
 
 # Check the results.
 FOREACH(p ${PACKAGES})

+ 1 - 0
Tests/FindPackageTest/SystemPackage/CMakeTestSystemPackageConfig.cmake

@@ -0,0 +1 @@
+# Test config file.