Browse Source

find_package: Restore component requirements in nested calls

Fix logic to populate required and optional components from CMake
variables when `find_package` is called in a nested context.

This was broken in commit e2a6416622 (find_package: Refactor in support
of recursion, 2024-11-29, v4.0.0-rc1~356^2), which promoted the
component sets from locals (in cmFindPackageCommand::InitialPass) to
member variables. Previously, in a nested context, these sets were
simply not filled, and we relied on the variables indicating component
requirement to already be set. When logic was added to properly fill the
sets (which is needed for CPS), it blindly dumped all components into
the required set, without actually checking whether the context had
marked the components as required or optional.

Fixes: #26824
Matthew Woehlke 8 months ago
parent
commit
37823b366f

+ 9 - 3
Source/cmFindPackageCommand.cxx

@@ -911,10 +911,16 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
         this->VersionExact = this->Makefile->IsOn(exact);
       }
       if (this->Components.empty()) {
-        std::string const components_var = this->Name + "_FIND_COMPONENTS";
-        this->Components = this->Makefile->GetSafeDefinition(components_var);
+        std::string const componentsVar = this->Name + "_FIND_COMPONENTS";
+        this->Components = this->Makefile->GetSafeDefinition(componentsVar);
         for (auto const& component : cmList{ this->Components }) {
-          this->RequiredComponents.insert(component);
+          std::string const crVar =
+            cmStrCat(this->Name, "_FIND_REQUIRED_"_s, component);
+          if (this->Makefile->GetDefinition(crVar).IsOn()) {
+            this->RequiredComponents.insert(component);
+          } else {
+            this->OptionalComponents.insert(component);
+          }
         }
       }
     }

+ 3 - 0
Tests/RunCMake/find_package/ComponentRecursion-stdout.txt

@@ -0,0 +1,3 @@
+-- ComponentTest_FIND_REQUIRED_A '1'
+-- ComponentTest_FIND_REQUIRED_B '0'
+-- ComponentTest_FIND_REQUIRED_C '0'

+ 2 - 0
Tests/RunCMake/find_package/ComponentRecursion.cmake

@@ -0,0 +1,2 @@
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})
+find_package(ComponentTest MODULE REQUIRED COMPONENTS A OPTIONAL_COMPONENTS B C)

+ 5 - 0
Tests/RunCMake/find_package/ComponentTestConfig.cmake

@@ -0,0 +1,5 @@
+foreach(c IN LISTS ComponentTest_FIND_COMPONENTS)
+  message(STATUS
+    "ComponentTest_FIND_REQUIRED_${c} "
+    "'${ComponentTest_FIND_REQUIRED_${c}}'")
+endforeach()

+ 2 - 0
Tests/RunCMake/find_package/FindComponentTest.cmake

@@ -0,0 +1,2 @@
+find_package(ComponentTest CONFIG
+   NO_DEFAULT_PATH PATHS ${CMAKE_CURRENT_LIST_DIR})

+ 1 - 0
Tests/RunCMake/find_package/RunCMakeTest.cmake

@@ -2,6 +2,7 @@ include(RunCMake)
 
 run_cmake(CMP0074-WARN)
 run_cmake(CMP0074-OLD)
+run_cmake(ComponentRecursion)
 run_cmake(ComponentRequiredAndOptional)
 run_cmake(EmptyRoots)
 run_cmake(FromPATHEnv)