# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
# file LICENSE.rst or https://cmake.org/licensing for details.

#[=======================================================================[.rst:
CMakeDependentOption
--------------------

Macro to provide an option dependent on other options.

This macro presents an option to the user only if a set of other
conditions are true.

.. command:: cmake_dependent_option

  .. code-block:: cmake

    cmake_dependent_option(<option> "<help_text>" <value> <depends> <force>)

  Makes ``<option>`` available to the user if the
  :ref:`semicolon-separated list <CMake Language Lists>` of conditions in
  ``<depends>`` are all true.  Otherwise, a local variable named ``<option>``
  is set to ``<force>``.

  When ``<option>`` is available, the given ``<help_text>`` and initial
  ``<value>`` are used. Otherwise, any value set by the user is preserved for
  when ``<depends>`` is satisfied in the future.

  Note that the ``<option>`` variable only has a value which satisfies the
  ``<depends>`` condition within the scope of the caller because it is a local
  variable.

.. versionadded:: 3.22

  Full :ref:`Condition Syntax` is now supported.  See policy :policy:`CMP0127`.

Examples
^^^^^^^^

Semicolon-separated list of conditions:

.. code-block:: cmake

  cmake_dependent_option(USE_FOO "Use Foo" ON "USE_BAR;NOT USE_ZOT" OFF)

If ``USE_BAR`` is true and ``USE_ZOT`` is false, this provides an option called
``USE_FOO`` that defaults to ON. Otherwise, it sets ``USE_FOO`` to OFF and
hides the option from the user. If the status of ``USE_BAR`` or ``USE_ZOT``
ever changes, any value for the ``USE_FOO`` option is saved so that when the
option is re-enabled it retains its old value.

Full condition syntax:

.. code-block:: cmake

  cmake_dependent_option(USE_FOO "Use Foo" ON "USE_A AND (USE_B OR USE_C)" OFF)

Similar to the previous example, if the argument with full condition syntax
evaluates to true, this provides an option called ``USE_FOO`` that defaults to
ON. Otherwise, it sets ``USE_FOO`` to OFF and hides the option from the user in
the GUI. When condition changes, option is saved in similar way as described
above. This enables using entire condition syntax as being the ``if`` clause
argument, such as grouping conditions with parens and similar.
#]=======================================================================]

macro(CMAKE_DEPENDENT_OPTION option doc default depends force)
  cmake_policy(GET CMP0127 _CDO_CMP0127
    PARENT_SCOPE # undocumented, do not use outside of CMake
    )
  if(${option}_ISSET MATCHES "^${option}_ISSET$")
    set(${option}_AVAILABLE 1)
    if("x${_CDO_CMP0127}x" STREQUAL "xNEWx")
      foreach(d ${depends})
        cmake_language(EVAL CODE "
          if (${d})
          else()
            set(${option}_AVAILABLE 0)
          endif()"
        )
      endforeach()
    else()
      foreach(d ${depends})
        string(REGEX REPLACE " +" ";" CMAKE_DEPENDENT_OPTION_DEP "${d}")
        if(${CMAKE_DEPENDENT_OPTION_DEP})
        else()
          set(${option}_AVAILABLE 0)
        endif()
      endforeach()
    endif()
    if(${option}_AVAILABLE)
      option(${option} "${doc}" "${default}")
      set(${option} "${${option}}" CACHE BOOL "${doc}" FORCE)
    else()
      if(${option} MATCHES "^${option}$")
      else()
        set(${option} "${${option}}" CACHE INTERNAL "${doc}")
      endif()
      set(${option} ${force})
    endif()
  else()
    set(${option} "${${option}_ISSET}")
  endif()
  if("x${_CDO_CMP0127}x" STREQUAL "xx" AND "x${depends}x" MATCHES "[^A-Za-z0-9_.; ]")
    cmake_policy(GET_WARNING CMP0127 _CDO_CMP0127_WARNING)
    message(AUTHOR_WARNING "${_CDO_CMP0127_WARNING}")
  endif()
  unset(_CDO_CMP0127)
endmacro()
