Browse Source

ENH: Help recursive find_package calls in modules

These changes teach find_package to behave nicely when invoked
recursively inside a find-module for the same package.  The module will
never be recursively loaded again.  Version arguments are automatically
forwarded.
Brad King 17 years ago
parent
commit
79e9b75558

+ 41 - 3
Source/cmFindPackageCommand.cxx

@@ -129,7 +129,8 @@ cmFindPackageCommand::cmFindPackageCommand()
     "                NO_CMAKE_FIND_ROOT_PATH])\n"
     "The NO_MODULE option may be used to skip Module mode explicitly.  "
     "It is also implied by use of options not specified in the reduced "
-    "signature.  "
+    "signature, or when the command is invoked recursively inside a "
+    "find-module for the package."
     "\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 "
@@ -160,6 +161,10 @@ cmFindPackageCommand::cmFindPackageCommand()
     "version (format is major[.minor[.patch[.tweak]]]).  "
     "If the EXACT option is given only a version of the package claiming "
     "an exact match of the requested version may be found.  "
+    "If no [version] is given to a recursive invocation inside a "
+    "find-module, the [version] and EXACT arguments are forwarded "
+    "automatically from the outer call."
+    "\n"
     "CMake does not establish any convention for the meaning of version "
     "numbers.  "
     "Package version numbers are checked by \"version\" files provided by "
@@ -476,6 +481,33 @@ bool cmFindPackageCommand
       cmake::AUTHOR_WARNING, "Ignoring EXACT since no version is requested.");
     }
 
+  if(!this->NoModule || this->Version.empty())
+    {
+    // Check whether we are recursing inside "Find<name>.cmake" within
+    // another find_package(<name>) call.
+    std::string mod = this->Name;
+    mod += "_FIND_MODULE";
+    if(this->Makefile->IsOn(mod.c_str()))
+      {
+      // Avoid recursing back into the module.
+      this->NoModule = true;
+
+      // Get version information from the outer call if necessary.
+      if(this->Version.empty())
+        {
+        // Requested version string.
+        std::string ver = this->Name;
+        ver += "_FIND_VERSION";
+        this->Version = this->Makefile->GetSafeDefinition(ver.c_str());
+
+        // Whether an exact version is required.
+        std::string exact = this->Name;
+        exact += "_FIND_VERSION_EXACT";
+        this->VersionExact = this->Makefile->IsOn(exact.c_str());
+        }
+      }
+    }
+
   if(!this->Version.empty())
     {
     // Try to parse the version number and store the results that were
@@ -611,9 +643,15 @@ bool cmFindPackageCommand::FindModule(bool& found)
   std::string mfile = this->Makefile->GetModulesFile(module.c_str());
   if ( mfile.size() )
     {
-    // Load the module we found.
+    // Load the module we found, and set "<name>_FIND_MODULE" to true
+    // while inside it.
     found = true;
-    return this->ReadListFile(mfile.c_str());
+    std::string var = this->Name;
+    var += "_FIND_MODULE";
+    this->Makefile->AddDefinition(var.c_str(), "1");
+    bool result = this->ReadListFile(mfile.c_str());
+    this->Makefile->RemoveDefinition(var.c_str());
+    return result;
     }
   return true;
 }

+ 9 - 0
Tests/FindPackageTest/CMakeLists.txt

@@ -38,6 +38,7 @@ SET(PACKAGES
   foo Foo Bar TFramework Tframework TApp Tapp Special
   VersionedA VersionedB
   wibbleA wibbleB
+  RecursiveA RecursiveB RecursiveC
   )
 FOREACH(p ${PACKAGES})
   SET(${p}_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
@@ -65,6 +66,11 @@ LIST(INSERT CMAKE_SYSTEM_PREFIX_PATH 0 "${CMAKE_CURRENT_SOURCE_DIR}/A")
 FIND_PACKAGE(wibbleA NAMES wibble PATHS B)
 FIND_PACKAGE(wibbleB NAMES wibble HINTS B)
 
+# Look for package with recursive find-modules.
+FIND_PACKAGE(RecursiveA)
+FIND_PACKAGE(RecursiveB 2)
+FIND_PACKAGE(RecursiveC 3.1 EXACT)
+
 # 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")
@@ -82,6 +88,9 @@ SET(VersionedA_EXPECTED "lib/zot-2.0/zot-config.cmake")
 SET(VersionedB_EXPECTED "lib/zot-3.1/zot-config.cmake")
 SET(wibbleA_EXPECTED "A/wibble-config.cmake")
 SET(wibbleB_EXPECTED "B/wibble-config.cmake")
+SET(RecursiveA_EXPECTED "lib/RecursiveA/recursivea-config.cmake")
+SET(RecursiveB_EXPECTED "lib/zot-2.0/zot-config.cmake")
+SET(RecursiveC_EXPECTED "lib/zot-3.1/zot-config.cmake")
 
 # Check the results.
 FOREACH(p ${PACKAGES})

+ 1 - 0
Tests/FindPackageTest/FindRecursiveA.cmake

@@ -0,0 +1 @@
+FIND_PACKAGE(RecursiveA)

+ 1 - 0
Tests/FindPackageTest/FindRecursiveB.cmake

@@ -0,0 +1 @@
+FIND_PACKAGE(RecursiveB NAMES zot)

+ 1 - 0
Tests/FindPackageTest/FindRecursiveC.cmake

@@ -0,0 +1 @@
+FIND_PACKAGE(RecursiveC NAMES zot)

+ 1 - 0
Tests/FindPackageTest/lib/RecursiveA/recursivea-config.cmake

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