diff options
-rw-r--r-- | Source/cmFindPackageCommand.cxx | 115 | ||||
-rw-r--r-- | Source/cmFindPackageCommand.h | 10 | ||||
-rw-r--r-- | Tests/FindPackageTest/CMakeLists.txt | 41 | ||||
-rw-r--r-- | Tests/FindPackageTest/SystemPackage/CMakeTestSystemPackageConfig.cmake | 1 |
4 files changed, 137 insertions, 30 deletions
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index d3c4bc7..b77273c 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/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] diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h index 19d2b10..4229d37 100644 --- a/Source/cmFindPackageCommand.h +++ b/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; diff --git a/Tests/FindPackageTest/CMakeLists.txt b/Tests/FindPackageTest/CMakeLists.txt index d4984d7..89383a0 100644 --- a/Tests/FindPackageTest/CMakeLists.txt +++ b/Tests/FindPackageTest/CMakeLists.txt @@ -38,6 +38,38 @@ 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}) diff --git a/Tests/FindPackageTest/SystemPackage/CMakeTestSystemPackageConfig.cmake b/Tests/FindPackageTest/SystemPackage/CMakeTestSystemPackageConfig.cmake new file mode 100644 index 0000000..deffa57 --- /dev/null +++ b/Tests/FindPackageTest/SystemPackage/CMakeTestSystemPackageConfig.cmake @@ -0,0 +1 @@ +# Test config file. |