summaryrefslogtreecommitdiff
path: root/Modules/CheckPIESupported.cmake
blob: 6d63f0bada8a1dd18b463c12e0d46d0c5ad3c943 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.

#[=======================================================================[.rst:
CheckPIESupported
-----------------

Check whether the linker supports Position Independent Code (PIE) or No
Position Independent Code (NO_PIE) for executables.
Use this to ensure that the :prop_tgt:`POSITION_INDEPENDENT_CODE` target
property for executables will be honored at link time.

.. command:: check_pie_supported

  ::

    check_pie_supported([OUTPUT_VARIABLE <output>]
                        [LANGUAGES <lang>...])

  Options are:

  ``OUTPUT_VARIABLE <output>``
    Set ``<output>`` variable with details about any error.
  ``LANGUAGES <lang>...``
    Check the linkers used for each of the specified languages.
    Supported languages are ``C``, ``CXX``, and ``Fortran``.

It makes no sense to use this module when :policy:`CMP0083` is set to ``OLD``,
so the command will return an error in this case.  See policy :policy:`CMP0083`
for details.

Variables
^^^^^^^^^

For each language checked, two boolean cache variables are defined.

 ``CMAKE_<lang>_LINK_PIE_SUPPORTED``
   Set to ``YES`` if ``PIE`` is supported by the linker and ``NO`` otherwise.
 ``CMAKE_<lang>_LINK_NO_PIE_SUPPORTED``
   Set to ``YES`` if ``NO_PIE`` is supported by the linker and ``NO`` otherwise.

Examples
^^^^^^^^

.. code-block:: cmake

  check_pie_supported()
  set_property(TARGET foo PROPERTY POSITION_INDEPENDENT_CODE TRUE)

.. code-block:: cmake

  # Retrieve any error message.
  check_pie_supported(OUTPUT_VARIABLE output LANGUAGES C)
  set_property(TARGET foo PROPERTY POSITION_INDEPENDENT_CODE TRUE)
  if(NOT CMAKE_C_LINK_PIE_SUPPORTED)
    message(WARNING "PIE is not supported at link time: ${output}.\n"
                    "PIE link options will not be passed to linker.")
  endif()

#]=======================================================================]


include (Internal/CMakeCheckCompilerFlag)

function (check_pie_supported)
  cmake_policy(GET CMP0083 cmp0083)

  if (NOT cmp0083)
    message(FATAL_ERROR "check_pie_supported: Policy CMP0083 is not set")
  endif()

  if(cmp0083 STREQUAL "OLD")
    message(FATAL_ERROR "check_pie_supported: Policy CMP0083 set to OLD")
  endif()

  set(optional)
  set(one OUTPUT_VARIABLE)
  set(multiple LANGUAGES)

  cmake_parse_arguments(CHECK_PIE "${optional}" "${one}" "${multiple}" "${ARGN}")
  if(CHECK_PIE_UNPARSED_ARGUMENTS)
    message(FATAL_ERROR "check_pie_supported: Unparsed arguments: ${CHECK_PIE_UNPARSED_ARGUMENTS}")
  endif()

  if (CHECK_PIE_LANGUAGES)
    set (unsupported_languages "${CHECK_PIE_LANGUAGES}")
    list (REMOVE_ITEM unsupported_languages "C" "CXX" "Fortran")
    if(unsupported_languages)
      message(FATAL_ERROR "check_pie_supported: language(s) '${unsupported_languages}' not supported")
    endif()
  else()
    # User did not set any languages, use defaults
    get_property (enabled_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
    if (NOT enabled_languages)
      return()
    endif()

    list (FILTER enabled_languages INCLUDE REGEX "^(C|CXX|Fortran)$")
    if (NOT enabled_languages)
      return()
    endif()

    set (CHECK_PIE_LANGUAGES ${enabled_languages})
  endif()

  set (outputs)

  foreach(lang IN LISTS CHECK_PIE_LANGUAGES)
    if(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER)
      cmake_check_compiler_flag(${lang} "${CMAKE_${lang}_LINK_OPTIONS_PIE}"
                                CMAKE_${lang}_LINK_PIE_SUPPORTED
                                OUTPUT_VARIABLE output)
      if (NOT CMAKE_${lang}_LINK_PIE_SUPPORTED)
        string (APPEND outputs "PIE (${lang}): ${output}\n")
      endif()

      cmake_check_compiler_flag(${lang} "${CMAKE_${lang}_LINK_OPTIONS_NO_PIE}"
                                CMAKE_${lang}_LINK_NO_PIE_SUPPORTED
                                OUTPUT_VARIABLE output)
      if (NOT CMAKE_${lang}_LINK_NO_PIE_SUPPORTED)
        string (APPEND outputs "NO_PIE (${lang}): ${output}\n")
      endif()
    else()
      # no support at link time. Set cache variables to NO
      set(CMAKE_${lang}_LINK_PIE_SUPPORTED NO CACHE INTERNAL "PIE (${lang})")
      set(CMAKE_${lang}_LINK_NO_PIE_SUPPORTED NO CACHE INTERNAL "NO_PIE (${lang})")
      string (APPEND outputs "PIE and NO_PIE are not supported by linker for ${lang}")
    endif()
  endforeach()

  if (CHECK_PIE_OUTPUT_VARIABLE)
    set (${CHECK_PIE_OUTPUT_VARIABLE} "${outputs}" PARENT_SCOPE)
  endif()
endfunction()