CMakePushCheckState.cmake 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. # file LICENSE.rst or https://cmake.org/licensing for details.
  3. include_guard(GLOBAL)
  4. #[=======================================================================[.rst:
  5. CMakePushCheckState
  6. -------------------
  7. This module provides commands for managing the state of variables that influence
  8. how various CMake check commands (e.g., :command:`check_symbol_exists`, etc.)
  9. are performed.
  10. Load this module in a CMake project with:
  11. .. code-block:: cmake
  12. include(CMakePushCheckState)
  13. This module provides the following commands, which are useful for scoped
  14. configuration, for example, in CMake modules or when performing checks in a
  15. controlled environment, ensuring that temporary modifications are isolated
  16. to the scope of the check and do not propagate into other parts of the build
  17. system:
  18. * :command:`cmake_push_check_state`
  19. * :command:`cmake_reset_check_state`
  20. * :command:`cmake_pop_check_state`
  21. Affected Variables
  22. ^^^^^^^^^^^^^^^^^^
  23. The following CMake variables are saved, reset, and restored by this module's
  24. commands:
  25. .. include:: /module/include/CMAKE_REQUIRED_FLAGS.rst
  26. .. include:: /module/include/CMAKE_REQUIRED_DEFINITIONS.rst
  27. .. include:: /module/include/CMAKE_REQUIRED_INCLUDES.rst
  28. .. include:: /module/include/CMAKE_REQUIRED_LINK_OPTIONS.rst
  29. .. include:: /module/include/CMAKE_REQUIRED_LIBRARIES.rst
  30. .. include:: /module/include/CMAKE_REQUIRED_LINK_DIRECTORIES.rst
  31. .. include:: /module/include/CMAKE_REQUIRED_QUIET.rst
  32. ``CMAKE_EXTRA_INCLUDE_FILES``
  33. .. versionadded:: 3.6
  34. Previously used already by the :command:`check_type_size` command; now
  35. also supported by this module.
  36. A :ref:`semicolon-separated list <CMake Language Lists>` of extra header
  37. files to include when performing the check.
  38. .. note::
  39. Other CMake variables, such as :variable:`CMAKE_<LANG>_FLAGS`, propagate
  40. to all checks regardless of commands provided by this module, as those
  41. fundamental variables are designed to influence the global state of the
  42. build system.
  43. Commands
  44. ^^^^^^^^
  45. .. command:: cmake_push_check_state
  46. Pushes (saves) the current states of the above variables onto a stack:
  47. .. code-block:: cmake
  48. cmake_push_check_state([RESET])
  49. Use this command to preserve the current configuration before making
  50. temporary modifications for specific checks.
  51. ``RESET``
  52. When this option is specified, the command not only saves the current states
  53. of the listed variables but also resets them to empty, allowing them to be
  54. reconfigured from a clean state.
  55. .. command:: cmake_reset_check_state
  56. Resets (clears) the contents of the variables listed above to empty states:
  57. .. code-block:: cmake
  58. cmake_reset_check_state()
  59. Use this command when performing multiple sequential checks that require
  60. entirely new configurations, ensuring no previous configuration
  61. unintentionally carries over.
  62. .. command:: cmake_pop_check_state
  63. Restores the states of the variables listed above to their values at the time
  64. of the most recent ``cmake_push_check_state()`` call:
  65. .. code-block:: cmake
  66. cmake_pop_check_state()
  67. Use this command to revert temporary changes made during a check. To
  68. prevent unexpected behavior, pair each ``cmake_push_check_state()`` with a
  69. corresponding ``cmake_pop_check_state()``.
  70. Examples
  71. ^^^^^^^^
  72. Example: Isolated Check With Compile Definitions
  73. """"""""""""""""""""""""""""""""""""""""""""""""
  74. In the following example, a check for the C symbol ``memfd_create()`` is
  75. performed with an additional ``_GNU_SOURCE`` compile definition, without
  76. affecting global compile flags. The ``RESET`` option is used to ensure
  77. that any prior values of the check-related variables are explicitly cleared
  78. before the check.
  79. .. code-block:: cmake
  80. include(CMakePushCheckState)
  81. # Save and reset the current state
  82. cmake_push_check_state(RESET)
  83. # Perform check with specific compile definitions
  84. set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
  85. include(CheckSymbolExists)
  86. check_symbol_exists(memfd_create "sys/mman.h" HAVE_MEMFD_CREATE)
  87. # Restore the original state
  88. cmake_pop_check_state()
  89. Example: Nested Configuration Scopes
  90. """"""""""""""""""""""""""""""""""""
  91. In the following example, variable states are pushed onto the stack multiple
  92. times, allowing for sequential or nested checks. Each
  93. ``cmake_pop_check_state()`` restores the most recent pushed states.
  94. .. code-block:: cmake
  95. include(CMakePushCheckState)
  96. # Save and reset the current state
  97. cmake_push_check_state(RESET)
  98. # Perform the first check with additional libraries
  99. set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_DL_LIBS})
  100. include(CheckSymbolExists)
  101. check_symbol_exists(dlopen "dlfcn.h" HAVE_DLOPEN)
  102. # Save current state
  103. cmake_push_check_state()
  104. # Perform the second check with libraries and additional compile definitions
  105. set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
  106. check_symbol_exists(dladdr "dlfcn.h" HAVE_DLADDR)
  107. message(STATUS "${CMAKE_REQUIRED_DEFINITIONS}")
  108. # Output: -D_GNU_SOURCE
  109. # Restore the previous state
  110. cmake_pop_check_state()
  111. message(STATUS "${CMAKE_REQUIRED_DEFINITIONS}")
  112. # Output here is empty
  113. # Reset variables to prepare for the next check
  114. cmake_reset_check_state()
  115. # Perform the next check only with additional compile definitions
  116. set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
  117. check_symbol_exists(dl_iterate_phdr "link.h" HAVE_DL_ITERATE_PHDR)
  118. # Restore the original state
  119. cmake_pop_check_state()
  120. #]=======================================================================]
  121. macro(CMAKE_RESET_CHECK_STATE)
  122. set(CMAKE_EXTRA_INCLUDE_FILES)
  123. set(CMAKE_REQUIRED_INCLUDES)
  124. set(CMAKE_REQUIRED_DEFINITIONS)
  125. set(CMAKE_REQUIRED_LINK_OPTIONS)
  126. set(CMAKE_REQUIRED_LIBRARIES)
  127. set(CMAKE_REQUIRED_LINK_DIRECTORIES)
  128. set(CMAKE_REQUIRED_FLAGS)
  129. set(CMAKE_REQUIRED_QUIET)
  130. endmacro()
  131. macro(CMAKE_PUSH_CHECK_STATE)
  132. if(NOT DEFINED _CMAKE_PUSH_CHECK_STATE_COUNTER)
  133. set(_CMAKE_PUSH_CHECK_STATE_COUNTER 0)
  134. endif()
  135. math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER "${_CMAKE_PUSH_CHECK_STATE_COUNTER}+1")
  136. set(_CMAKE_EXTRA_INCLUDE_FILES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_EXTRA_INCLUDE_FILES})
  137. set(_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_INCLUDES})
  138. set(_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_DEFINITIONS})
  139. set(_CMAKE_REQUIRED_LINK_OPTIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_LINK_OPTIONS})
  140. set(_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_LIBRARIES})
  141. set(_CMAKE_REQUIRED_LINK_DIRECTORIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_LINK_DIRECTORIES})
  142. set(_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_FLAGS})
  143. set(_CMAKE_REQUIRED_QUIET_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER} ${CMAKE_REQUIRED_QUIET})
  144. if (${ARGC} GREATER 0 AND "${ARGV0}" STREQUAL "RESET")
  145. cmake_reset_check_state()
  146. endif()
  147. endmacro()
  148. macro(CMAKE_POP_CHECK_STATE)
  149. # don't pop more than we pushed
  150. if("${_CMAKE_PUSH_CHECK_STATE_COUNTER}" GREATER "0")
  151. set(CMAKE_EXTRA_INCLUDE_FILES ${_CMAKE_EXTRA_INCLUDE_FILES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
  152. set(CMAKE_REQUIRED_INCLUDES ${_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
  153. set(CMAKE_REQUIRED_DEFINITIONS ${_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
  154. set(CMAKE_REQUIRED_LINK_OPTIONS ${_CMAKE_REQUIRED_LINK_OPTIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
  155. set(CMAKE_REQUIRED_LIBRARIES ${_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
  156. set(CMAKE_REQUIRED_LINK_DIRECTORIES ${_CMAKE_REQUIRED_LINK_DIRECTORIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
  157. set(CMAKE_REQUIRED_FLAGS ${_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
  158. set(CMAKE_REQUIRED_QUIET ${_CMAKE_REQUIRED_QUIET_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})
  159. math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER "${_CMAKE_PUSH_CHECK_STATE_COUNTER}-1")
  160. endif()
  161. endmacro()