فهرست منبع

Merge topic 'find-package-required'

857a039d66 find_*: Add variable to default calls to REQUIRED

Acked-by: Kitware Robot <[email protected]>
Acked-by: buildbot <[email protected]>
Merge-request: !10364
Brad King 11 ماه پیش
والد
کامیت
75da788360
38فایلهای تغییر یافته به همراه337 افزوده شده و 22 حذف شده
  1. 13 1
      Help/command/FIND_XXX.txt
  2. 12 2
      Help/command/find_package.rst
  3. 1 0
      Help/manual/cmake-variables.7.rst
  4. 8 0
      Help/release/dev/cmake-find-required.rst
  5. 27 0
      Help/variable/CMAKE_FIND_REQUIRED.rst
  6. 18 0
      Source/cmFindBase.cxx
  7. 53 17
      Source/cmFindPackageCommand.cxx
  8. 12 2
      Source/cmFindPackageCommand.h
  9. 1 0
      Tests/RunCMake/find_file/Optional-result.txt
  10. 10 0
      Tests/RunCMake/find_file/Optional-stderr.txt
  11. 14 0
      Tests/RunCMake/find_file/Optional.cmake
  12. 1 0
      Tests/RunCMake/find_file/RunCMakeTest.cmake
  13. 1 0
      Tests/RunCMake/find_library/Optional-result.txt
  14. 10 0
      Tests/RunCMake/find_library/Optional-stderr.txt
  15. 13 0
      Tests/RunCMake/find_library/Optional.cmake
  16. 1 0
      Tests/RunCMake/find_library/RunCMakeTest.cmake
  17. 4 0
      Tests/RunCMake/find_package/MissingNormalForceRequired-stderr.txt
  18. 1 0
      Tests/RunCMake/find_package/PackageVarOverridesOptional-result.txt
  19. 20 0
      Tests/RunCMake/find_package/PackageVarOverridesOptional-stderr.txt
  20. 2 0
      Tests/RunCMake/find_package/PackageVarOverridesOptional.cmake
  21. 1 0
      Tests/RunCMake/find_package/RequiredOptionalKeywordsClash-result.txt
  22. 4 0
      Tests/RunCMake/find_package/RequiredOptionalKeywordsClash-stderr.txt
  23. 1 0
      Tests/RunCMake/find_package/RequiredOptionalKeywordsClash.cmake
  24. 18 0
      Tests/RunCMake/find_package/RequiredVarNested-stderr.txt
  25. 3 0
      Tests/RunCMake/find_package/RequiredVarNested.cmake
  26. 8 0
      Tests/RunCMake/find_package/RequiredVarNestedConfig.cmake
  27. 1 0
      Tests/RunCMake/find_package/RequiredVarOptional-result.txt
  28. 21 0
      Tests/RunCMake/find_package/RequiredVarOptional-stderr.txt
  29. 4 0
      Tests/RunCMake/find_package/RequiredVarOptional.cmake
  30. 4 0
      Tests/RunCMake/find_package/RunCMakeTest.cmake
  31. 1 0
      Tests/RunCMake/find_path/Optional-result.txt
  32. 10 0
      Tests/RunCMake/find_path/Optional-stderr.txt
  33. 13 0
      Tests/RunCMake/find_path/Optional.cmake
  34. 1 0
      Tests/RunCMake/find_path/RunCMakeTest.cmake
  35. 1 0
      Tests/RunCMake/find_program/Optional-result.txt
  36. 10 0
      Tests/RunCMake/find_program/Optional-stderr.txt
  37. 13 0
      Tests/RunCMake/find_program/Optional.cmake
  38. 1 0
      Tests/RunCMake/find_program/RunCMakeTest.cmake

+ 13 - 1
Help/command/FIND_XXX.txt

@@ -18,7 +18,7 @@ The general signature is:
              [VALIDATOR function]
              [VALIDATOR function]
              [DOC "cache documentation string"]
              [DOC "cache documentation string"]
              [NO_CACHE]
              [NO_CACHE]
-             [REQUIRED]
+             [REQUIRED|OPTIONAL]
              [NO_DEFAULT_PATH]
              [NO_DEFAULT_PATH]
              [NO_PACKAGE_ROOT_PATH]
              [NO_PACKAGE_ROOT_PATH]
              [NO_CMAKE_PATH]
              [NO_CMAKE_PATH]
@@ -118,6 +118,18 @@ Options include:
   the search will be attempted again the next time |FIND_XXX| is invoked
   the search will be attempted again the next time |FIND_XXX| is invoked
   with the same variable.
   with the same variable.
 
 
+  .. versionadded:: 4.1
+
+    Every |FIND_XXX| command will be treated as ``REQUIRED`` when the
+    :variable:`CMAKE_FIND_REQUIRED` variable is enabled.
+
+``OPTIONAL``
+  .. versionadded:: 4.1
+
+  Ignore the value of :variable:`CMAKE_FIND_REQUIRED` and
+  continue without an error message if nothing is found.
+  Incompatible with ``REQUIRED``.
+
 If ``NO_DEFAULT_PATH`` is specified, then no additional paths are
 If ``NO_DEFAULT_PATH`` is specified, then no additional paths are
 added to the search.
 added to the search.
 If ``NO_DEFAULT_PATH`` is not specified, the search process is as follows:
 If ``NO_DEFAULT_PATH`` is not specified, the search process is as follows:

+ 12 - 2
Help/command/find_package.rst

@@ -132,7 +132,7 @@ Basic Signature
 .. code-block:: cmake
 .. code-block:: cmake
 
 
   find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
   find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
-               [REQUIRED] [[COMPONENTS] [components...]]
+               [REQUIRED|OPTIONAL] [[COMPONENTS] [components...]]
                [OPTIONAL_COMPONENTS components...]
                [OPTIONAL_COMPONENTS components...]
                [REGISTRY_VIEW  (64|32|64_32|32_64|HOST|TARGET|BOTH)]
                [REGISTRY_VIEW  (64|32|64_32|32_64|HOST|TARGET|BOTH)]
                [GLOBAL]
                [GLOBAL]
@@ -159,6 +159,13 @@ otherwise execution still continues.  As a form of shorthand, if the
 ``REQUIRED`` option is present, the ``COMPONENTS`` keyword can be omitted
 ``REQUIRED`` option is present, the ``COMPONENTS`` keyword can be omitted
 and the required components can be listed directly after ``REQUIRED``.
 and the required components can be listed directly after ``REQUIRED``.
 
 
+The :variable:`CMAKE_FIND_REQUIRED` variable can be enabled to make this call
+``REQUIRED`` by default. This behavior can be overridden by providing the
+``OPTIONAL`` keyword. As with the ``REQUIRED`` option, a list of components
+can be listed directly after ``OPTIONAL``, which is equivalent to listing
+them after the ``COMPONENTS`` keyword. When the ``OPTIONAL`` keyword is given,
+the warning output when a package is not found is suppressed.
+
 Additional optional components may be listed after
 Additional optional components may be listed after
 ``OPTIONAL_COMPONENTS``.  If these cannot be satisfied, the package overall
 ``OPTIONAL_COMPONENTS``.  If these cannot be satisfied, the package overall
 can still be considered found, as long as all required components are
 can still be considered found, as long as all required components are
@@ -249,7 +256,7 @@ Full Signature
 .. code-block:: cmake
 .. code-block:: cmake
 
 
   find_package(<PackageName> [version] [EXACT] [QUIET]
   find_package(<PackageName> [version] [EXACT] [QUIET]
-               [REQUIRED] [[COMPONENTS] [components...]]
+               [REQUIRED|OPTIONAL] [[COMPONENTS] [components...]]
                [OPTIONAL_COMPONENTS components...]
                [OPTIONAL_COMPONENTS components...]
                [CONFIG|NO_MODULE]
                [CONFIG|NO_MODULE]
                [GLOBAL]
                [GLOBAL]
@@ -635,6 +642,9 @@ Every non-REQUIRED ``find_package`` call can be disabled or made REQUIRED:
 
 
 Setting both variables to ``TRUE`` simultaneously is an error.
 Setting both variables to ``TRUE`` simultaneously is an error.
 
 
+The :variable:`CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>` variable takes priority
+over the ``OPTIONAL`` keyword in determining whether a package is required.
+
 .. _`version selection`:
 .. _`version selection`:
 
 
 Config Mode Version Selection
 Config Mode Version Selection

+ 1 - 0
Help/manual/cmake-variables.7.rst

@@ -61,6 +61,7 @@ Variables that Provide Information
    /variable/CMAKE_FIND_PACKAGE_REDIRECTS_DIR
    /variable/CMAKE_FIND_PACKAGE_REDIRECTS_DIR
    /variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION
    /variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION
    /variable/CMAKE_FIND_PACKAGE_SORT_ORDER
    /variable/CMAKE_FIND_PACKAGE_SORT_ORDER
+   /variable/CMAKE_FIND_REQUIRED
    /variable/CMAKE_GENERATOR
    /variable/CMAKE_GENERATOR
    /variable/CMAKE_GENERATOR_INSTANCE
    /variable/CMAKE_GENERATOR_INSTANCE
    /variable/CMAKE_GENERATOR_PLATFORM
    /variable/CMAKE_GENERATOR_PLATFORM

+ 8 - 0
Help/release/dev/cmake-find-required.rst

@@ -0,0 +1,8 @@
+cmake-find-required
+-------------------
+
+* The :variable:`CMAKE_FIND_REQUIRED` variable was added to tell
+  :command:`find_package`, :command:`find_path`, :command:`find_file`,
+  :command:`find_library`, and :command:`find_program` to be ``REQUIRED``
+  by default.  The commands also gained an ``OPTIONAL`` keyword to ignore
+  the variable for a specific call.

+ 27 - 0
Help/variable/CMAKE_FIND_REQUIRED.rst

@@ -0,0 +1,27 @@
+CMAKE_FIND_REQUIRED
+-------------------
+
+.. versionadded:: 4.1
+
+If enabled, the following commands are treated as having the ``REQUIRED``
+keyword unless provided with the ``OPTIONAL`` keyword:
+
+* :command:`find_package`
+* :command:`find_program`
+* :command:`find_library`
+* :command:`find_path`
+* :command:`find_file`
+
+When :command:`find_package` loads a ``Find<PackageName>.cmake``
+or ``<PackageName>Config.cmake`` module, the ``CMAKE_FIND_REQUIRED``
+variable is automatically unset within it to restore the default
+behavior for nested find operations.  The module is free to set the
+``CMAKE_FIND_REQUIRED`` variable itself to opt-in to the behavior.
+
+Note that enabling this variable breaks some commonly used patterns.
+Multiple calls to :command:`find_package` are sometimes used to obtain a
+different search order to the default.
+
+See also the :variable:`CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>` for making
+a :command:`find_package` call ``REQUIRED``, and for additional information on
+how enabling these variables can break commonly used patterns.

+ 18 - 0
Source/cmFindBase.cxx

@@ -94,6 +94,7 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
   this->SelectDefaultMacMode();
   this->SelectDefaultMacMode();
 
 
   bool newStyle = false;
   bool newStyle = false;
+  bool haveRequiredOrOptional = false;
   enum Doing
   enum Doing
   {
   {
     DoingNone,
     DoingNone,
@@ -129,8 +130,21 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
       this->NoDefaultPath = true;
       this->NoDefaultPath = true;
     } else if (args[j] == "REQUIRED") {
     } else if (args[j] == "REQUIRED") {
       doing = DoingNone;
       doing = DoingNone;
+      if (haveRequiredOrOptional && !this->Required) {
+        this->SetError("cannot be both REQUIRED and OPTIONAL");
+        return false;
+      }
       this->Required = true;
       this->Required = true;
       newStyle = true;
       newStyle = true;
+      haveRequiredOrOptional = true;
+    } else if (args[j] == "OPTIONAL") {
+      doing = DoingNone;
+      if (haveRequiredOrOptional && this->Required) {
+        this->SetError("cannot be both REQUIRED and OPTIONAL");
+        return false;
+      }
+      newStyle = true;
+      haveRequiredOrOptional = true;
     } else if (args[j] == "REGISTRY_VIEW") {
     } else if (args[j] == "REGISTRY_VIEW") {
       if (++j == args.size()) {
       if (++j == args.size()) {
         this->SetError("missing required argument for REGISTRY_VIEW");
         this->SetError("missing required argument for REGISTRY_VIEW");
@@ -187,6 +201,10 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
     }
     }
   }
   }
 
 
+  if (!haveRequiredOrOptional) {
+    this->Required = this->Makefile->IsOn("CMAKE_FIND_REQUIRED");
+  }
+
   if (this->VariableDocumentation.empty()) {
   if (this->VariableDocumentation.empty()) {
     this->VariableDocumentation = "Where can ";
     this->VariableDocumentation = "Where can ";
     if (this->Names.empty()) {
     if (this->Names.empty()) {

+ 53 - 17
Source/cmFindPackageCommand.cxx

@@ -747,7 +747,18 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
       configArgs.push_back(i);
       configArgs.push_back(i);
       doing = DoingNone;
       doing = DoingNone;
     } else if (args[i] == "REQUIRED") {
     } else if (args[i] == "REQUIRED") {
-      this->Required = true;
+      if (this->Required == RequiredStatus::OptionalExplicit) {
+        this->SetError("cannot be both REQUIRED and OPTIONAL");
+        return false;
+      }
+      this->Required = RequiredStatus::RequiredExplicit;
+      doing = DoingComponents;
+    } else if (args[i] == "OPTIONAL") {
+      if (this->Required == RequiredStatus::RequiredExplicit) {
+        this->SetError("cannot be both REQUIRED and OPTIONAL");
+        return false;
+      }
+      this->Required = RequiredStatus::OptionalExplicit;
       doing = DoingComponents;
       doing = DoingComponents;
     } else if (args[i] == "COMPONENTS") {
     } else if (args[i] == "COMPONENTS") {
       doing = DoingComponents;
       doing = DoingComponents;
@@ -844,6 +855,11 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
     }
     }
   }
   }
 
 
+  if (this->Required == RequiredStatus::Optional &&
+      this->Makefile->IsOn("CMAKE_FIND_REQUIRED")) {
+    this->Required = RequiredStatus::RequiredFromFindVar;
+  }
+
   if (!this->GlobalScope) {
   if (!this->GlobalScope) {
     cmValue value(
     cmValue value(
       this->Makefile->GetDefinition("CMAKE_FIND_PACKAGE_TARGETS_GLOBAL"));
       this->Makefile->GetDefinition("CMAKE_FIND_PACKAGE_TARGETS_GLOBAL"));
@@ -978,21 +994,21 @@ bool cmFindPackageCommand::FindPackage(
   bool const makePackageRequiredSet =
   bool const makePackageRequiredSet =
     this->Makefile->IsOn(makePackageRequiredVar);
     this->Makefile->IsOn(makePackageRequiredVar);
   if (makePackageRequiredSet) {
   if (makePackageRequiredSet) {
-    if (this->Required) {
+    if (this->IsRequired()) {
       this->Makefile->IssueMessage(
       this->Makefile->IssueMessage(
         MessageType::WARNING,
         MessageType::WARNING,
         cmStrCat("for module ", this->Name,
         cmStrCat("for module ", this->Name,
                  " already called with REQUIRED, thus ",
                  " already called with REQUIRED, thus ",
                  makePackageRequiredVar, " has no effect."));
                  makePackageRequiredVar, " has no effect."));
     } else {
     } else {
-      this->Required = true;
+      this->Required = RequiredStatus::RequiredFromPackageVar;
     }
     }
   }
   }
 
 
   std::string const disableFindPackageVar =
   std::string const disableFindPackageVar =
     cmStrCat("CMAKE_DISABLE_FIND_PACKAGE_", this->Name);
     cmStrCat("CMAKE_DISABLE_FIND_PACKAGE_", this->Name);
   if (this->Makefile->IsOn(disableFindPackageVar)) {
   if (this->Makefile->IsOn(disableFindPackageVar)) {
-    if (this->Required) {
+    if (this->IsRequired()) {
       this->SetError(
       this->SetError(
         cmStrCat("for module ", this->Name,
         cmStrCat("for module ", this->Name,
                  (makePackageRequiredSet
                  (makePackageRequiredSet
@@ -1310,6 +1326,9 @@ void cmFindPackageCommand::SetModuleVariables()
 {
 {
   this->AddFindDefinition("CMAKE_FIND_PACKAGE_NAME", this->Name);
   this->AddFindDefinition("CMAKE_FIND_PACKAGE_NAME", this->Name);
 
 
+  // Nested find calls are not automatically required.
+  this->AddFindDefinition("CMAKE_FIND_REQUIRED", ""_s);
+
   // Store the list of components and associated variable definitions.
   // Store the list of components and associated variable definitions.
   std::string components_var = this->Name + "_FIND_COMPONENTS";
   std::string components_var = this->Name + "_FIND_COMPONENTS";
   this->AddFindDefinition(components_var, this->Components);
   this->AddFindDefinition(components_var, this->Components);
@@ -1329,7 +1348,7 @@ void cmFindPackageCommand::SetModuleVariables()
     this->AddFindDefinition(quietly, "1"_s);
     this->AddFindDefinition(quietly, "1"_s);
   }
   }
 
 
-  if (this->Required) {
+  if (this->IsRequired()) {
     // Tell the module that is about to be read that it should report
     // Tell the module that is about to be read that it should report
     // a fatal error if the package is not found.
     // a fatal error if the package is not found.
     std::string req = cmStrCat(this->Name, "_FIND_REQUIRED");
     std::string req = cmStrCat(this->Name, "_FIND_REQUIRED");
@@ -1575,11 +1594,13 @@ bool cmFindPackageCommand::HandlePackageMode(
 
 
   // package not found
   // package not found
   if (result && !found) {
   if (result && !found) {
-    // warn if package required or neither quiet nor in config mode
-    if (this->Required ||
-        !(this->Quiet ||
-          (this->UseConfigFiles && !this->UseFindModules &&
-           this->ConsideredConfigs.empty()))) {
+    // warn if package required or
+    // (neither quiet nor in config mode and not explicitly optional)
+    if (this->IsRequired() ||
+        (!(this->Quiet ||
+           (this->UseConfigFiles && !this->UseFindModules &&
+            this->ConsideredConfigs.empty())) &&
+         this->Required != RequiredStatus::OptionalExplicit)) {
       // The variable is not set.
       // The variable is not set.
       std::ostringstream e;
       std::ostringstream e;
       std::ostringstream aw;
       std::ostringstream aw;
@@ -1675,11 +1696,19 @@ bool cmFindPackageCommand::HandlePackageMode(
                "without ensuring that it is actually available.\n";
                "without ensuring that it is actually available.\n";
         }
         }
       }
       }
+      if (this->Required == RequiredStatus::RequiredFromFindVar) {
+        e << "\nThis package is considered required because the "
+             "CMAKE_FIND_REQUIRED variable has been enabled.\n";
+      } else if (this->Required == RequiredStatus::RequiredFromPackageVar) {
+        e << "\nThis package is considered required because the "
+          << cmStrCat("CMAKE_REQUIRE_FIND_PACKAGE_", this->Name)
+          << " variable has been enabled.\n";
+      }
 
 
-      this->Makefile->IssueMessage(this->Required ? MessageType::FATAL_ERROR
-                                                  : MessageType::WARNING,
-                                   e.str());
-      if (this->Required) {
+      this->Makefile->IssueMessage(
+        this->IsRequired() ? MessageType::FATAL_ERROR : MessageType::WARNING,
+        e.str());
+      if (this->IsRequired()) {
         cmSystemTools::SetFatalErrorOccurred();
         cmSystemTools::SetFatalErrorOccurred();
       }
       }
 
 
@@ -1912,7 +1941,7 @@ bool cmFindPackageCommand::ReadPackage()
   // Loop over appendices.
   // Loop over appendices.
   auto iter = this->CpsAppendices.begin();
   auto iter = this->CpsAppendices.begin();
   while (iter != this->CpsAppendices.end()) {
   while (iter != this->CpsAppendices.end()) {
-    bool required = false;
+    RequiredStatus required = RequiredStatus::Optional;
     bool important = false;
     bool important = false;
 
 
     // Check if this appendix provides any requested components.
     // Check if this appendix provides any requested components.
@@ -1972,7 +2001,7 @@ bool cmFindPackageCommand::ReadPackage()
 
 
 bool cmFindPackageCommand::FindPackageDependencies(
 bool cmFindPackageCommand::FindPackageDependencies(
   std::string const& fileName, cmPackageInfoReader const& reader,
   std::string const& fileName, cmPackageInfoReader const& reader,
-  bool required)
+  RequiredStatus required)
 {
 {
   // Get package requirements.
   // Get package requirements.
   for (cmPackageRequirement const& dep : reader.GetRequirements()) {
   for (cmPackageRequirement const& dep : reader.GetRequirements()) {
@@ -2110,7 +2139,7 @@ void cmFindPackageCommand::AppendSuccessInformation()
   }
   }
   this->Makefile->GetState()->SetGlobalProperty(versionInfoPropName,
   this->Makefile->GetState()->SetGlobalProperty(versionInfoPropName,
                                                 versionInfo);
                                                 versionInfo);
-  if (this->Required) {
+  if (this->IsRequired()) {
     std::string const requiredInfoPropName =
     std::string const requiredInfoPropName =
       cmStrCat("_CMAKE_", this->Name, "_TYPE");
       cmStrCat("_CMAKE_", this->Name, "_TYPE");
     this->Makefile->GetState()->SetGlobalProperty(requiredInfoPropName,
     this->Makefile->GetState()->SetGlobalProperty(requiredInfoPropName,
@@ -3265,6 +3294,13 @@ bool cmFindPackageCommand::SearchEnvironmentPrefix(std::string const& prefix)
   return TryGeneratedPaths(searchFn, pdt::Cps, prefix, pkgDirGen);
   return TryGeneratedPaths(searchFn, pdt::Cps, prefix, pkgDirGen);
 }
 }
 
 
+bool cmFindPackageCommand::IsRequired() const
+{
+  return this->Required == RequiredStatus::RequiredExplicit ||
+    this->Required == RequiredStatus::RequiredFromPackageVar ||
+    this->Required == RequiredStatus::RequiredFromFindVar;
+}
+
 // TODO: Debug cmsys::Glob double slash problem.
 // TODO: Debug cmsys::Glob double slash problem.
 
 
 bool cmFindPackage(std::vector<std::string> const& args,
 bool cmFindPackage(std::vector<std::string> const& args,

+ 12 - 2
Source/cmFindPackageCommand.h

@@ -151,9 +151,17 @@ private:
   using AppendixMap = std::map<std::string, Appendix>;
   using AppendixMap = std::map<std::string, Appendix>;
   AppendixMap FindAppendices(std::string const& base,
   AppendixMap FindAppendices(std::string const& base,
                              cmPackageInfoReader const& baseReader) const;
                              cmPackageInfoReader const& baseReader) const;
+  enum RequiredStatus
+  {
+    Optional,
+    OptionalExplicit,
+    RequiredExplicit,
+    RequiredFromPackageVar,
+    RequiredFromFindVar
+  };
   bool FindPackageDependencies(std::string const& fileName,
   bool FindPackageDependencies(std::string const& fileName,
                                cmPackageInfoReader const& reader,
                                cmPackageInfoReader const& reader,
-                               bool required);
+                               RequiredStatus required);
 
 
   bool ImportPackageTargets(std::string const& fileName,
   bool ImportPackageTargets(std::string const& fileName,
                             cmPackageInfoReader& reader);
                             cmPackageInfoReader& reader);
@@ -194,6 +202,8 @@ private:
   bool SearchAppBundlePrefix(std::string const& prefix);
   bool SearchAppBundlePrefix(std::string const& prefix);
   bool SearchEnvironmentPrefix(std::string const& prefix);
   bool SearchEnvironmentPrefix(std::string const& prefix);
 
 
+  bool IsRequired() const;
+
   struct OriginalDef
   struct OriginalDef
   {
   {
     bool exists;
     bool exists;
@@ -234,7 +244,7 @@ private:
   unsigned int VersionFoundCount = 0;
   unsigned int VersionFoundCount = 0;
   KWIML_INT_uint64_t RequiredCMakeVersion = 0;
   KWIML_INT_uint64_t RequiredCMakeVersion = 0;
   bool Quiet = false;
   bool Quiet = false;
-  bool Required = false;
+  RequiredStatus Required = RequiredStatus::Optional;
   bool UseCpsFiles = false;
   bool UseCpsFiles = false;
   bool UseConfigFiles = true;
   bool UseConfigFiles = true;
   bool UseFindModules = true;
   bool UseFindModules = true;

+ 1 - 0
Tests/RunCMake/find_file/Optional-result.txt

@@ -0,0 +1 @@
+1

+ 10 - 0
Tests/RunCMake/find_file/Optional-stderr.txt

@@ -0,0 +1,10 @@
+CMake Error at Optional.cmake:[0-9]+ \(find_file\):
+  find_file cannot be both REQUIRED and OPTIONAL
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
+
+
+CMake Error at Optional\.cmake:[0-9]+ \(find_file\):
+  Could not find FILE_doNotExists using the following files: doNotExists.h
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)

+ 14 - 0
Tests/RunCMake/find_file/Optional.cmake

@@ -0,0 +1,14 @@
+set(CMAKE_FIND_REQUIRED ON)
+find_file(FILE_doNotExists_Optional
+  NAMES doNotExists.h
+  OPTIONAL
+)
+find_file(FILE_doNotExists_OptionalRequired
+  NAMES doNotExists.h
+  OPTIONAL
+  REQUIRED
+)
+find_file(FILE_doNotExists
+  NAMES doNotExists.h
+  REQUIRED
+)

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

@@ -4,6 +4,7 @@ run_cmake(FromPATHEnv)
 run_cmake(FromPrefixPath)
 run_cmake(FromPrefixPath)
 run_cmake(PrefixInPATH)
 run_cmake(PrefixInPATH)
 run_cmake(Required)
 run_cmake(Required)
+run_cmake(Optional)
 run_cmake(NO_CACHE)
 run_cmake(NO_CACHE)
 run_cmake(REGISTRY_VIEW-no-view)
 run_cmake(REGISTRY_VIEW-no-view)
 run_cmake(REGISTRY_VIEW-wrong-view)
 run_cmake(REGISTRY_VIEW-wrong-view)

+ 1 - 0
Tests/RunCMake/find_library/Optional-result.txt

@@ -0,0 +1 @@
+1

+ 10 - 0
Tests/RunCMake/find_library/Optional-stderr.txt

@@ -0,0 +1,10 @@
+CMake Error at Optional.cmake:[0-9]+ \(find_library\):
+  find_library cannot be both REQUIRED and OPTIONAL
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
+
+
+CMake Error at Optional\.cmake:[0-9]+ \(find_library\):
+  Could not find LIB_doNotExists using the following names: doNotExists
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)

+ 13 - 0
Tests/RunCMake/find_library/Optional.cmake

@@ -0,0 +1,13 @@
+set(CMAKE_FIND_REQUIRED ON)
+find_library(LIB_doNotExists_Optional
+  NAMES doNotExists
+  OPTIONAL
+)
+find_library(LIB_doNotExists_OptionalRequired
+  NAMES doNotExists
+  OPTIONAL
+  REQUIRED
+)
+find_library(LIB_doNotExists
+  NAMES doNotExists
+)

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

@@ -12,6 +12,7 @@ if(UNIX AND NOT CYGWIN)
 endif()
 endif()
 run_cmake(PrefixInPATH)
 run_cmake(PrefixInPATH)
 run_cmake(Required)
 run_cmake(Required)
+run_cmake(Optional)
 run_cmake(NO_CACHE)
 run_cmake(NO_CACHE)
 run_cmake(REGISTRY_VIEW-no-view)
 run_cmake(REGISTRY_VIEW-no-view)
 run_cmake(REGISTRY_VIEW-wrong-view)
 run_cmake(REGISTRY_VIEW-wrong-view)

+ 4 - 0
Tests/RunCMake/find_package/MissingNormalForceRequired-stderr.txt

@@ -1,5 +1,9 @@
 CMake Error at MissingNormalForceRequired.cmake:2 \(find_package\):
 CMake Error at MissingNormalForceRequired.cmake:2 \(find_package\):
   No "FindNotHere.cmake" found in CMAKE_MODULE_PATH\.
   No "FindNotHere.cmake" found in CMAKE_MODULE_PATH\.
+
+  This package is considered required because the
+  CMAKE_REQUIRE_FIND_PACKAGE_NotHere variable has been enabled.
+
 Call Stack \(most recent call first\):
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
   CMakeLists.txt:3 \(include\)
 +
 +

+ 1 - 0
Tests/RunCMake/find_package/PackageVarOverridesOptional-result.txt

@@ -0,0 +1 @@
+1

+ 20 - 0
Tests/RunCMake/find_package/PackageVarOverridesOptional-stderr.txt

@@ -0,0 +1,20 @@
+CMake Error at PackageVarOverridesOptional.cmake:[0-9]+ \(find_package\):
+  By not providing "FindFoo.cmake" in CMAKE_MODULE_PATH this project has
+  asked CMake to find a package configuration file provided by "Foo", but
+  CMake did not find one.
+
+  Could not find a package configuration file provided by "Foo" with any of
+  the following names:
+
+    FooConfig.cmake
+    foo-config.cmake
+
+  Add the installation prefix of "Foo" to CMAKE_PREFIX_PATH or set "Foo_DIR"
+  to a directory containing one of the above files.  If "Foo" provides a
+  separate development package or SDK, be sure it has been installed.
+
+  This package is considered required because the
+  CMAKE_REQUIRE_FIND_PACKAGE_Foo variable has been enabled.
+
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

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

@@ -0,0 +1,2 @@
+set(CMAKE_REQUIRE_FIND_PACKAGE_Foo ON)
+find_package(Foo OPTIONAL)

+ 1 - 0
Tests/RunCMake/find_package/RequiredOptionalKeywordsClash-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/find_package/RequiredOptionalKeywordsClash-stderr.txt

@@ -0,0 +1,4 @@
+CMake Error at RequiredOptionalKeywordsClash.cmake:[0-9]+ \(find_package\):
+  find_package cannot be both REQUIRED and OPTIONAL
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)

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

@@ -0,0 +1 @@
+find_package(Foo OPTIONAL REQUIRED)

+ 18 - 0
Tests/RunCMake/find_package/RequiredVarNested-stderr.txt

@@ -0,0 +1,18 @@
+CMake Warning at RequiredVarNestedConfig\.cmake:[0-9]+ \(find_package\):
+  By not providing "FindDoesNotExist\.cmake" in CMAKE_MODULE_PATH this project
+  has asked CMake to find a package configuration file provided by
+  "DoesNotExist", but CMake did not find one\.
+
+  Could not find a package configuration file provided by "DoesNotExist" with
+  any of the following names:
+
+    DoesNotExistConfig.cmake
+    doesnotexist-config.cmake
+
+  Add the installation prefix of "DoesNotExist" to CMAKE_PREFIX_PATH or set
+  "DoesNotExist_DIR" to a directory containing one of the above files\.  If
+  "DoesNotExist" provides a separate development package or SDK, be sure it
+  has been installed\.
+Call Stack \(most recent call first\):
+  RequiredVarNested.cmake:[0-9]+ \(find_package\)
+  CMakeLists\.txt:[0-9]+ \(include\)

+ 3 - 0
Tests/RunCMake/find_package/RequiredVarNested.cmake

@@ -0,0 +1,3 @@
+set(CMAKE_FIND_REQUIRED ON CACHE BOOL "") # The cache entry must be shadowed by a nested definition.
+set(RequiredVarNested_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+find_package(RequiredVarNested CONFIG)

+ 8 - 0
Tests/RunCMake/find_package/RequiredVarNestedConfig.cmake

@@ -0,0 +1,8 @@
+if (CMAKE_FIND_REQUIRED)
+  message(FATAL_ERROR "CMAKE_FIND_REQUIRED enabled in Config.cmake")
+endif()
+find_package(DoesNotExist)
+find_library(library DoesNotExist)
+find_program(program DoesNotExist)
+find_path(path DoesNotExist)
+find_file(file DoesNotExist)

+ 1 - 0
Tests/RunCMake/find_package/RequiredVarOptional-result.txt

@@ -0,0 +1 @@
+1

+ 21 - 0
Tests/RunCMake/find_package/RequiredVarOptional-stderr.txt

@@ -0,0 +1,21 @@
+CMake Error at RequiredVarOptional.cmake:[0-9]+ \(find_package\):
+  By not providing "FindDoesNotExist.cmake" in CMAKE_MODULE_PATH this project
+  has asked CMake to find a package configuration file provided by
+  "DoesNotExist", but CMake did not find one.
+
+  Could not find a package configuration file provided by "DoesNotExist" with
+  any of the following names:
+
+    DoesNotExistConfig.cmake
+    doesnotexist-config.cmake
+
+  Add the installation prefix of "DoesNotExist" to CMAKE_PREFIX_PATH or set
+  "DoesNotExist_DIR" to a directory containing one of the above files.  If
+  "DoesNotExist" provides a separate development package or SDK, be sure it
+  has been installed.
+
+  This package is considered required because the CMAKE_FIND_REQUIRED
+  variable has been enabled.
+
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 4 - 0
Tests/RunCMake/find_package/RequiredVarOptional.cmake

@@ -0,0 +1,4 @@
+set(CMAKE_FIND_REQUIRED ON)
+find_package(DoesNotExist-Optional OPTIONAL CompA CompB CompC)
+find_package(DoesNotExist)
+message(FATAL_ERROR "This error must not be reachable.")

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

@@ -27,9 +27,13 @@ run_cmake_with_options(ModuleModeDebugPkg --debug-find-pkg=Foo,Zot)
 run_cmake(PackageRoot)
 run_cmake(PackageRoot)
 run_cmake(PackageRootNestedConfig)
 run_cmake(PackageRootNestedConfig)
 run_cmake(PackageRootNestedModule)
 run_cmake(PackageRootNestedModule)
+run_cmake(PackageVarOverridesOptional)
 run_cmake(PolicyPush)
 run_cmake(PolicyPush)
 run_cmake(PolicyPop)
 run_cmake(PolicyPop)
 run_cmake(RequiredOptionValuesClash)
 run_cmake(RequiredOptionValuesClash)
+run_cmake(RequiredOptionalKeywordsClash)
+run_cmake(RequiredVarOptional)
+run_cmake(RequiredVarNested)
 run_cmake(FindRootPathAndPrefixPathAreEqual)
 run_cmake(FindRootPathAndPrefixPathAreEqual)
 run_cmake(SetFoundFALSE)
 run_cmake(SetFoundFALSE)
 run_cmake(WrongVersion)
 run_cmake(WrongVersion)

+ 1 - 0
Tests/RunCMake/find_path/Optional-result.txt

@@ -0,0 +1 @@
+1

+ 10 - 0
Tests/RunCMake/find_path/Optional-stderr.txt

@@ -0,0 +1,10 @@
+CMake Error at Optional.cmake:[0-9]+ \(find_path\):
+  find_path cannot be both REQUIRED and OPTIONAL
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
+
+
+CMake Error at Optional\.cmake:[0-9]+ \(find_path\):
+  Could not find PATH_doNotExists using the following files: doNotExists.h
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)

+ 13 - 0
Tests/RunCMake/find_path/Optional.cmake

@@ -0,0 +1,13 @@
+set(CMAKE_FIND_REQUIRED ON)
+find_path(PATH_doNotExists_Optional
+  NAMES doNotExists.h
+  OPTIONAL
+)
+find_path(PATH_doNotExists_OptionalRequired
+  NAMES doNotExists.h
+  OPTIONAL
+  REQUIRED
+)
+find_path(PATH_doNotExists
+  NAMES doNotExists.h
+)

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

@@ -4,6 +4,7 @@ run_cmake(EmptyOldStyle)
 run_cmake(FromPATHEnv)
 run_cmake(FromPATHEnv)
 run_cmake(PrefixInPATH)
 run_cmake(PrefixInPATH)
 run_cmake(Required)
 run_cmake(Required)
+run_cmake(Optional)
 run_cmake(NO_CACHE)
 run_cmake(NO_CACHE)
 run_cmake(REGISTRY_VIEW-no-view)
 run_cmake(REGISTRY_VIEW-no-view)
 run_cmake(REGISTRY_VIEW-wrong-view)
 run_cmake(REGISTRY_VIEW-wrong-view)

+ 1 - 0
Tests/RunCMake/find_program/Optional-result.txt

@@ -0,0 +1 @@
+1

+ 10 - 0
Tests/RunCMake/find_program/Optional-stderr.txt

@@ -0,0 +1,10 @@
+CMake Error at Optional.cmake:[0-9]+ \(find_program\):
+  find_program cannot be both REQUIRED and OPTIONAL
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
+
+
+CMake Error at Optional\.cmake:[0-9]+ \(find_program\):
+  Could not find PROG_AandB using the following names: testAandB
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)

+ 13 - 0
Tests/RunCMake/find_program/Optional.cmake

@@ -0,0 +1,13 @@
+set(CMAKE_FIND_REQUIRED ON)
+find_program(PROG_AandB_Optional
+  NAMES testAandB
+  OPTIONAL
+)
+find_program(PROG_AandB_OptionalRequired
+  NAMES testAandB
+  OPTIONAL
+  REQUIRED
+)
+find_program(PROG_AandB
+  NAMES testAandB
+)

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

@@ -5,6 +5,7 @@ run_cmake(DirsPerName)
 run_cmake(NamesPerDir)
 run_cmake(NamesPerDir)
 run_cmake(RelAndAbsPath)
 run_cmake(RelAndAbsPath)
 run_cmake(Required)
 run_cmake(Required)
+run_cmake(Optional)
 run_cmake(NO_CACHE)
 run_cmake(NO_CACHE)
 run_cmake(IgnorePrefixPath)
 run_cmake(IgnorePrefixPath)
 run_cmake(REGISTRY_VIEW-no-view)
 run_cmake(REGISTRY_VIEW-no-view)