Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Modules / CheckTypeSize.cmake
1 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2 # file Copyright.txt or https://cmake.org/licensing for details.
3
4 #[=======================================================================[.rst:
5 CheckTypeSize
6 -------------
7
8 Check sizeof a type
9
10 .. command:: check_type_size
11
12   .. code-block:: cmake
13
14     check_type_size(<type> <variable> [BUILTIN_TYPES_ONLY]
15                                       [LANGUAGE <language>])
16
17   Check if the type exists and determine its size.  Results are reported
18   in the following variables:
19
20   ``HAVE_<variable>``
21     Holds a true or false value indicating whether the type exists.
22
23   ``<variable>``
24     Holds one of the following values:
25
26     ``<size>``
27        Type has non-zero size ``<size>``.
28
29     ``0``
30        Type has architecture-dependent size.  This may occur when
31        :variable:`CMAKE_OSX_ARCHITECTURES` has multiple architectures.
32        In this case ``<variable>_CODE`` contains C preprocessor tests
33        mapping from each architecture macro to the corresponding type size.
34        The list of architecture macros is stored in ``<variable>_KEYS``,
35        and the value for each key is stored in ``<variable>-<key>``.
36
37     "" (empty string)
38        Type does not exist.
39
40   ``<variable>_CODE``
41     Holds C preprocessor code to define the macro ``<variable>`` to the size
42     of the type, or to leave the macro undefined if the type does not exist.
43
44   The options are:
45
46   ``BUILTIN_TYPES_ONLY``
47
48     Support only compiler-builtin types.  If *not* given, the macro checks
49     for headers ``<sys/types.h>``, ``<stdint.h>``, and ``<stddef.h>``, and
50     saves results in ``HAVE_SYS_TYPES_H``, ``HAVE_STDINT_H``, and
51     ``HAVE_STDDEF_H``.  The type size check automatically includes the
52     available headers, thus supporting checks of types defined in the headers.
53
54   ``LANGUAGE <language>``
55     Use the ``<language>`` compiler to perform the check.
56     Acceptable values are ``C`` and ``CXX``.
57
58 Despite the name of the macro you may use it to check the size of more
59 complex expressions, too.  To check e.g.  for the size of a struct
60 member you can do something like this:
61
62 .. code-block:: cmake
63
64   check_type_size("((struct something*)0)->member" SIZEOF_MEMBER)
65
66
67 The following variables may be set before calling this macro to modify
68 the way the check is run:
69
70 ``CMAKE_REQUIRED_FLAGS``
71   string of compile command line flags.
72 ``CMAKE_REQUIRED_DEFINITIONS``
73   list of macros to define (-DFOO=bar).
74 ``CMAKE_REQUIRED_INCLUDES``
75   list of include directories.
76 ``CMAKE_REQUIRED_LINK_OPTIONS``
77   .. versionadded:: 3.14
78     list of options to pass to link command.
79 ``CMAKE_REQUIRED_LIBRARIES``
80   list of libraries to link.
81 ``CMAKE_REQUIRED_QUIET``
82   .. versionadded:: 3.1
83     execute quietly without messages.
84 ``CMAKE_EXTRA_INCLUDE_FILES``
85   list of extra headers to include.
86 #]=======================================================================]
87
88 include(CheckIncludeFile)
89 include(CheckIncludeFileCXX)
90
91 get_filename_component(__check_type_size_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
92
93 include_guard(GLOBAL)
94
95 cmake_policy(PUSH)
96 cmake_policy(SET CMP0054 NEW)
97
98 #-----------------------------------------------------------------------------
99 # Helper function.  DO NOT CALL DIRECTLY.
100 function(__check_type_size_impl type var map builtin language)
101   if(NOT CMAKE_REQUIRED_QUIET)
102     message(CHECK_START "Check size of ${type}")
103   endif()
104
105   # Perform language check
106   if(language STREQUAL "C")
107     set(src ${var}.c)
108   elseif(language STREQUAL "CXX")
109     set(src ${var}.cpp)
110   else()
111     message(FATAL_ERROR "Unknown language:\n  ${language}\nSupported languages: C, CXX.\n")
112   endif()
113
114   # Include header files.
115   set(headers)
116   if(builtin)
117     if(language STREQUAL "CXX" AND type MATCHES "^std::")
118       if(HAVE_SYS_TYPES_H)
119         string(APPEND headers "#include <sys/types.h>\n")
120       endif()
121       if(HAVE_CSTDINT)
122         string(APPEND headers "#include <cstdint>\n")
123       endif()
124       if(HAVE_CSTDDEF)
125         string(APPEND headers "#include <cstddef>\n")
126       endif()
127     else()
128       if(HAVE_SYS_TYPES_H)
129         string(APPEND headers "#include <sys/types.h>\n")
130       endif()
131       if(HAVE_STDINT_H)
132         string(APPEND headers "#include <stdint.h>\n")
133       endif()
134       if(HAVE_STDDEF_H)
135         string(APPEND headers "#include <stddef.h>\n")
136       endif()
137     endif()
138   endif()
139   foreach(h ${CMAKE_EXTRA_INCLUDE_FILES})
140     string(APPEND headers "#include \"${h}\"\n")
141   endforeach()
142
143   # Perform the check.
144   set(bin ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckTypeSize/${var}.bin)
145   file(READ ${__check_type_size_dir}/CheckTypeSize.c.in src_content)
146   string(CONFIGURE "${src_content}" src_content @ONLY)
147   try_compile(HAVE_${var} SOURCE_FROM_VAR "${src}" src_content
148     COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
149     LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS}
150     LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}
151     CMAKE_FLAGS
152       "-DCOMPILE_DEFINITIONS:STRING=${CMAKE_REQUIRED_FLAGS}"
153       "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}"
154     OUTPUT_VARIABLE output
155     COPY_FILE ${bin}
156     )
157
158   if(HAVE_${var})
159     # The check compiled.  Load information from the binary.
160     file(STRINGS ${bin} strings LIMIT_COUNT 10 REGEX "INFO:size")
161
162     # Parse the information strings.
163     set(regex_size ".*INFO:size\\[0*([^]]*)\\].*")
164     set(regex_key " key\\[([^]]*)\\]")
165     set(keys)
166     set(code)
167     set(mismatch)
168     set(first 1)
169     foreach(info ${strings})
170       if("${info}" MATCHES "${regex_size}")
171         # Get the type size.
172         set(size "${CMAKE_MATCH_1}")
173         if(first)
174           set(${var} ${size})
175         elseif(NOT "${size}" STREQUAL "${${var}}")
176           set(mismatch 1)
177         endif()
178         set(first 0)
179
180         # Get the architecture map key.
181         string(REGEX MATCH   "${regex_key}"       key "${info}")
182         string(REGEX REPLACE "${regex_key}" "\\1" key "${key}")
183         if(key)
184           string(APPEND code "\nset(${var}-${key} \"${size}\")")
185           list(APPEND keys ${key})
186         endif()
187       endif()
188     endforeach()
189
190     # Update the architecture-to-size map.
191     if(mismatch AND keys)
192       configure_file(${__check_type_size_dir}/CheckTypeSizeMap.cmake.in ${map} @ONLY)
193       set(${var} 0)
194     else()
195       file(REMOVE ${map})
196     endif()
197
198     if(mismatch AND NOT keys)
199       message(SEND_ERROR "CHECK_TYPE_SIZE found different results, consider setting CMAKE_OSX_ARCHITECTURES or CMAKE_TRY_COMPILE_OSX_ARCHITECTURES to one or no architecture !")
200     endif()
201
202     if(NOT CMAKE_REQUIRED_QUIET)
203       message(CHECK_PASS "done")
204     endif()
205     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
206       "Determining size of ${type} passed with the following output:\n${output}\n\n")
207     set(${var} "${${var}}" CACHE INTERNAL "CHECK_TYPE_SIZE: sizeof(${type})")
208   else()
209     # The check failed to compile.
210     if(NOT CMAKE_REQUIRED_QUIET)
211       message(CHECK_FAIL "failed")
212     endif()
213     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
214       "Determining size of ${type} failed with the following output:\n${output}\n${src}:\n${src_content}\n\n")
215     set(${var} "" CACHE INTERNAL "CHECK_TYPE_SIZE: ${type} unknown")
216     file(REMOVE ${map})
217   endif()
218 endfunction()
219
220 #-----------------------------------------------------------------------------
221 macro(CHECK_TYPE_SIZE TYPE VARIABLE)
222   # parse arguments
223   unset(doing)
224   foreach(arg ${ARGN})
225     if("x${arg}" STREQUAL "xBUILTIN_TYPES_ONLY")
226       set(_CHECK_TYPE_SIZE_${arg} 1)
227       unset(doing)
228     elseif("x${arg}" STREQUAL "xLANGUAGE") # change to MATCHES for more keys
229       set(doing "${arg}")
230       set(_CHECK_TYPE_SIZE_${doing} "")
231     elseif("x${doing}" STREQUAL "xLANGUAGE")
232       set(_CHECK_TYPE_SIZE_${doing} "${arg}")
233       unset(doing)
234     else()
235       message(FATAL_ERROR "Unknown argument:\n  ${arg}\n")
236     endif()
237   endforeach()
238   if("x${doing}" MATCHES "^x(LANGUAGE)$")
239     message(FATAL_ERROR "Missing argument:\n  ${doing} arguments requires a value\n")
240   endif()
241   if(DEFINED _CHECK_TYPE_SIZE_LANGUAGE)
242     if(NOT "x${_CHECK_TYPE_SIZE_LANGUAGE}" MATCHES "^x(C|CXX)$")
243       message(FATAL_ERROR "Unknown language:\n  ${_CHECK_TYPE_SIZE_LANGUAGE}.\nSupported languages: C, CXX.\n")
244     endif()
245     set(_language ${_CHECK_TYPE_SIZE_LANGUAGE})
246   else()
247     set(_language C)
248   endif()
249
250   # Optionally check for standard headers.
251   if(_CHECK_TYPE_SIZE_BUILTIN_TYPES_ONLY)
252     set(_builtin 0)
253   else()
254     set(_builtin 1)
255     if(_language STREQUAL "C")
256       check_include_file(sys/types.h HAVE_SYS_TYPES_H)
257       check_include_file(stdint.h HAVE_STDINT_H)
258       check_include_file(stddef.h HAVE_STDDEF_H)
259     elseif(_language STREQUAL "CXX")
260       check_include_file_cxx(sys/types.h HAVE_SYS_TYPES_H)
261       if("${TYPE}" MATCHES "^std::")
262         check_include_file_cxx(cstdint HAVE_CSTDINT)
263         check_include_file_cxx(cstddef HAVE_CSTDDEF)
264       else()
265         check_include_file_cxx(stdint.h HAVE_STDINT_H)
266         check_include_file_cxx(stddef.h HAVE_STDDEF_H)
267       endif()
268     endif()
269   endif()
270   unset(_CHECK_TYPE_SIZE_BUILTIN_TYPES_ONLY)
271   unset(_CHECK_TYPE_SIZE_LANGUAGE)
272
273   # Compute or load the size or size map.
274   set(${VARIABLE}_KEYS)
275   set(_map_file ${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CheckTypeSize/${VARIABLE}.cmake)
276   if(NOT DEFINED HAVE_${VARIABLE})
277     __check_type_size_impl(${TYPE} ${VARIABLE} ${_map_file} ${_builtin} ${_language})
278   endif()
279   include(${_map_file} OPTIONAL)
280   set(_map_file)
281   set(_builtin)
282
283   # Create preprocessor code.
284   if(${VARIABLE}_KEYS)
285     set(${VARIABLE}_CODE)
286     set(_if if)
287     foreach(key ${${VARIABLE}_KEYS})
288       string(APPEND ${VARIABLE}_CODE "#${_if} defined(${key})\n# define ${VARIABLE} ${${VARIABLE}-${key}}\n")
289       set(_if elif)
290     endforeach()
291     string(APPEND ${VARIABLE}_CODE "#else\n# error ${VARIABLE} unknown\n#endif")
292     set(_if)
293   elseif(${VARIABLE})
294     set(${VARIABLE}_CODE "#define ${VARIABLE} ${${VARIABLE}}")
295   else()
296     set(${VARIABLE}_CODE "/* #undef ${VARIABLE} */")
297   endif()
298 endmacro()
299
300 #-----------------------------------------------------------------------------
301 cmake_policy(POP)