File: CheckPIESupported.cmake

package info (click to toggle)
cmake 4.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 147,284 kB
  • sloc: ansic: 403,915; cpp: 290,772; sh: 4,102; python: 3,357; yacc: 3,106; lex: 1,189; f90: 532; asm: 471; lisp: 375; cs: 270; java: 266; fortran: 230; perl: 217; objc: 215; xml: 198; makefile: 97; javascript: 83; pascal: 63; tcl: 55; php: 25; ruby: 22
file content (189 lines) | stat: -rw-r--r-- 6,646 bytes parent folder | download
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
# file LICENSE.rst or https://cmake.org/licensing for details.

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

.. versionadded:: 3.14

This module provides the ``check_pie_supported()`` function to check whether the
linker supports Position Independent Code (PIE) or No Position Independent Code
(NO_PIE) for executables.

When setting the :prop_tgt:`POSITION_INDEPENDENT_CODE` target property,
PIC-related compile and link options are added when building library objects,
and PIE-related compile options are added when building objects of executable
targets, regardless of this module.  Use this module to ensure that the
``POSITION_INDEPENDENT_CODE`` target property for executables is also honored at
link time.

.. command:: check_pie_supported

  .. code-block:: cmake

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

  Options are:

  ``OUTPUT_VARIABLE <output>``
    Set ``<output>`` variable with details about any error. If the check is
    bypassed because it uses cached results from a previous call, the output
    will be empty even if errors were present in the previous call.

  ``LANGUAGES <lang>...``
    Check the linkers used for each of the specified languages.
    If this option is not provided, the command checks all enabled languages.

    ``C``, ``CXX``, ``Fortran`` are supported.

    .. versionadded:: 3.23

      ``OBJC``, ``OBJCXX``, ``CUDA``, and ``HIP`` are supported.

  .. note::

    To use ``check_pie_supported()``, policy :policy:`CMP0083` must be set to
    ``NEW``; otherwise, a fatal error will occur.

Variables
^^^^^^^^^

For each language checked, the ``check_pie_supported()`` function defines two
boolean cache variables:

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

Examples
^^^^^^^^

To enable PIE on an executable target at link time as well, include this module
and call ``check_pie_supported()`` before setting the
``POSITION_INDEPENDENT_CODE`` target property.  This will determine whether the
linker for each checked language supports PIE-related link options.  For
example:

.. code-block:: cmake

  add_executable(foo ...)

  include(CheckPIESupported)
  check_pie_supported()
  set_property(TARGET foo PROPERTY POSITION_INDEPENDENT_CODE TRUE)

Since not all linkers require or support PIE-related link options (for example,
``MSVC``), retrieving any error messages might be useful for logging purposes:

.. code-block:: cmake

  add_executable(foo ...)

  include(CheckPIESupported)
  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:\n${output}"
                    "PIE link options will not be passed to linker.")
  endif()

Setting the ``POSITION_INDEPENDENT_CODE`` target property on an executable
without this module will set PIE-related compile options but not PIE-related
link options, which might not be sufficient in certain cases:

.. code-block:: cmake

  add_executable(foo ...)
  set_property(TARGET foo PROPERTY POSITION_INDEPENDENT_CODE TRUE)

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


include (Internal/CheckLinkerFlag)

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" "OBJC" "OBJCXX" "Fortran" "CUDA" "HIP")
    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|OBJC|OBJCXX|Fortran|CUDA|HIP)$")
    if (NOT enabled_languages)
      return()
    endif()

    set (CHECK_PIE_LANGUAGES ${enabled_languages})
  endif()

  set(CMAKE_REQUIRED_QUIET TRUE)
  set (outputs)

  # Isolate the checks below from the project's PIC selection.
  unset(CMAKE_POSITION_INDEPENDENT_CODE)

  foreach(lang IN LISTS CHECK_PIE_LANGUAGES)
    if(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER)
      if(NOT DEFINED CMAKE_${lang}_LINK_PIE_SUPPORTED)
        # ensure PIE compile flags are also used
        list(JOIN CMAKE_${lang}_COMPILE_OPTIONS_PIE " " CMAKE_REQUIRED_FLAGS)
        cmake_check_linker_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()
        unset(CMAKE_REQUIRED_FLAGS)
      endif()

      if(NOT DEFINED CMAKE_${lang}_LINK_NO_PIE_SUPPORTED)
        cmake_check_linker_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()
      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}\n")
    endif()
  endforeach()

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