CheckPIESupported.cmake 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. # file Copyright.txt or https://cmake.org/licensing for details.
  3. #[=======================================================================[.rst:
  4. CheckPIESupported
  5. -----------------
  6. .. versionadded:: 3.14
  7. Check whether the linker supports Position Independent Code (PIE) or No
  8. Position Independent Code (NO_PIE) for executables.
  9. Use this to ensure that the :prop_tgt:`POSITION_INDEPENDENT_CODE` target
  10. property for executables will be honored at link time.
  11. .. command:: check_pie_supported
  12. .. code-block:: cmake
  13. check_pie_supported([OUTPUT_VARIABLE <output>]
  14. [LANGUAGES <lang>...])
  15. Options are:
  16. ``OUTPUT_VARIABLE <output>``
  17. Set ``<output>`` variable with details about any error. If the check is
  18. bypassed because it uses cached results from a previous call, the output
  19. will be empty even if errors were present in the previous call.
  20. ``LANGUAGES <lang>...``
  21. Check the linkers used for each of the specified languages.
  22. If this option is not provided, the command checks all enabled languages.
  23. ``C``, ``CXX``, ``Fortran`` are supported.
  24. .. versionadded:: 3.23
  25. ``OBJC``, ``OBJCXX``, ``CUDA``, and ``HIP`` are supported.
  26. It makes no sense to use this module when :policy:`CMP0083` is set to ``OLD``,
  27. so the command will return an error in this case. See policy :policy:`CMP0083`
  28. for details.
  29. Variables
  30. ^^^^^^^^^
  31. For each language checked, two boolean cache variables are defined.
  32. ``CMAKE_<lang>_LINK_PIE_SUPPORTED``
  33. Set to true if ``PIE`` is supported by the linker and false otherwise.
  34. ``CMAKE_<lang>_LINK_NO_PIE_SUPPORTED``
  35. Set to true if ``NO_PIE`` is supported by the linker and false otherwise.
  36. Examples
  37. ^^^^^^^^
  38. .. code-block:: cmake
  39. check_pie_supported()
  40. set_property(TARGET foo PROPERTY POSITION_INDEPENDENT_CODE TRUE)
  41. .. code-block:: cmake
  42. # Retrieve any error message.
  43. check_pie_supported(OUTPUT_VARIABLE output LANGUAGES C)
  44. set_property(TARGET foo PROPERTY POSITION_INDEPENDENT_CODE TRUE)
  45. if(NOT CMAKE_C_LINK_PIE_SUPPORTED)
  46. message(WARNING "PIE is not supported at link time: ${output}.\n"
  47. "PIE link options will not be passed to linker.")
  48. endif()
  49. #]=======================================================================]
  50. include (Internal/CheckLinkerFlag)
  51. function (check_pie_supported)
  52. cmake_policy(GET CMP0083 cmp0083)
  53. if (NOT cmp0083)
  54. message(FATAL_ERROR "check_pie_supported: Policy CMP0083 is not set")
  55. endif()
  56. if(cmp0083 STREQUAL "OLD")
  57. message(FATAL_ERROR "check_pie_supported: Policy CMP0083 set to OLD")
  58. endif()
  59. set(optional)
  60. set(one OUTPUT_VARIABLE)
  61. set(multiple LANGUAGES)
  62. cmake_parse_arguments(CHECK_PIE "${optional}" "${one}" "${multiple}" "${ARGN}")
  63. if(CHECK_PIE_UNPARSED_ARGUMENTS)
  64. message(FATAL_ERROR "check_pie_supported: Unparsed arguments: ${CHECK_PIE_UNPARSED_ARGUMENTS}")
  65. endif()
  66. if (CHECK_PIE_LANGUAGES)
  67. set (unsupported_languages "${CHECK_PIE_LANGUAGES}")
  68. list (REMOVE_ITEM unsupported_languages "C" "CXX" "OBJC" "OBJCXX" "Fortran" "CUDA" "HIP")
  69. if(unsupported_languages)
  70. message(FATAL_ERROR "check_pie_supported: language(s) '${unsupported_languages}' not supported")
  71. endif()
  72. else()
  73. # User did not set any languages, use defaults
  74. get_property (enabled_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
  75. if (NOT enabled_languages)
  76. return()
  77. endif()
  78. list (FILTER enabled_languages INCLUDE REGEX "^(C|CXX|OBJC|OBJCXX|Fortran|CUDA|HIP)$")
  79. if (NOT enabled_languages)
  80. return()
  81. endif()
  82. set (CHECK_PIE_LANGUAGES ${enabled_languages})
  83. endif()
  84. set(CMAKE_REQUIRED_QUIET TRUE)
  85. set (outputs)
  86. foreach(lang IN LISTS CHECK_PIE_LANGUAGES)
  87. if(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER)
  88. if(NOT DEFINED CMAKE_${lang}_LINK_PIE_SUPPORTED)
  89. # ensure PIE compile flags are also used
  90. list(JOIN CMAKE_${lang}_COMPILE_OPTIONS_PIE " " CMAKE_REQUIRED_FLAGS)
  91. cmake_check_linker_flag(${lang}
  92. "${CMAKE_${lang}_LINK_OPTIONS_PIE}"
  93. CMAKE_${lang}_LINK_PIE_SUPPORTED
  94. OUTPUT_VARIABLE output)
  95. if (NOT CMAKE_${lang}_LINK_PIE_SUPPORTED)
  96. string (APPEND outputs "PIE (${lang}): ${output}\n")
  97. endif()
  98. unset(CMAKE_REQUIRED_FLAGS)
  99. endif()
  100. if(NOT DEFINED CMAKE_${lang}_LINK_NO_PIE_SUPPORTED)
  101. cmake_check_linker_flag(${lang}
  102. "${CMAKE_${lang}_LINK_OPTIONS_NO_PIE}"
  103. CMAKE_${lang}_LINK_NO_PIE_SUPPORTED
  104. OUTPUT_VARIABLE output)
  105. if (NOT CMAKE_${lang}_LINK_NO_PIE_SUPPORTED)
  106. string (APPEND outputs "NO_PIE (${lang}): ${output}\n")
  107. endif()
  108. endif()
  109. else()
  110. # no support at link time. Set cache variables to NO
  111. set(CMAKE_${lang}_LINK_PIE_SUPPORTED NO CACHE INTERNAL "PIE (${lang})")
  112. set(CMAKE_${lang}_LINK_NO_PIE_SUPPORTED NO CACHE INTERNAL "NO_PIE (${lang})")
  113. string (APPEND outputs "PIE and NO_PIE are not supported by linker for ${lang}\n")
  114. endif()
  115. endforeach()
  116. if (CHECK_PIE_OUTPUT_VARIABLE)
  117. set (${CHECK_PIE_OUTPUT_VARIABLE} "${outputs}" PARENT_SCOPE)
  118. endif()
  119. endfunction()