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