1#.rst:
2# CheckTypeSize
3# -------------
4#
5# Check sizeof a type
6#
7# ::
8#
9#   CHECK_TYPE_SIZE(TYPE VARIABLE [BUILTIN_TYPES_ONLY]
10#                                 [LANGUAGE <language>])
11#
12# Check if the type exists and determine its size.  On return,
13# "HAVE_${VARIABLE}" holds the existence of the type, and "${VARIABLE}"
14# holds one of the following:
15#
16# ::
17#
18#    <size> = type has non-zero size <size>
19#    "0"    = type has arch-dependent size (see below)
20#    ""     = type does not exist
21#
22# Both ``HAVE_${VARIABLE}`` and ``${VARIABLE}`` will be created as internal
23# cache variables.
24#
25# Furthermore, the variable "${VARIABLE}_CODE" holds C preprocessor code
26# to define the macro "${VARIABLE}" to the size of the type, or leave
27# the macro undefined if the type does not exist.
28#
29# The variable "${VARIABLE}" may be "0" when CMAKE_OSX_ARCHITECTURES has
30# multiple architectures for building OS X universal binaries.  This
31# indicates that the type size varies across architectures.  In this
32# case "${VARIABLE}_CODE" contains C preprocessor tests mapping from
33# each architecture macro to the corresponding type size.  The list of
34# architecture macros is stored in "${VARIABLE}_KEYS", and the value for
35# each key is stored in "${VARIABLE}-${KEY}".
36#
37# If the BUILTIN_TYPES_ONLY option is not given, the macro checks for
38# headers <sys/types.h>, <stdint.h>, and <stddef.h>, and saves results
39# in HAVE_SYS_TYPES_H, HAVE_STDINT_H, and HAVE_STDDEF_H.  The type size
40# check automatically includes the available headers, thus supporting
41# checks of types defined in the headers.
42#
43# If LANGUAGE is set, the specified compiler will be used to perform the
44# check. Acceptable values are C and CXX
45#
46# Despite the name of the macro you may use it to check the size of more
47# complex expressions, too.  To check e.g.  for the size of a struct
48# member you can do something like this:
49#
50# ::
51#
52#   check_type_size("((struct something*)0)->member" SIZEOF_MEMBER)
53#
54#
55#
56# The following variables may be set before calling this macro to modify
57# the way the check is run:
58#
59# ::
60#
61#   CMAKE_REQUIRED_FLAGS = string of compile command line flags
62#   CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
63#   CMAKE_REQUIRED_INCLUDES = list of include directories
64#   CMAKE_REQUIRED_LIBRARIES = list of libraries to link
65#   CMAKE_REQUIRED_QUIET = execute quietly without messages
66#   CMAKE_EXTRA_INCLUDE_FILES = list of extra headers to include
67
68#=============================================================================
69# Copyright 2002-2009 Kitware, Inc.
70#
71# Distributed under the OSI-approved BSD License (the "License");
72# see accompanying file Copyright.txt for details.
73#
74# This software is distributed WITHOUT ANY WARRANTY; without even the
75# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
76# See the License for more information.
77#=============================================================================
78# (To distribute this file outside of CMake, substitute the full
79#  License text for the above reference.)
80
81include(CheckIncludeFile)
82include(CheckIncludeFileCXX)
83
84cmake_policy(PUSH)
85cmake_policy(VERSION 3.0)
86
87get_filename_component(__check_type_size_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
88
89#-----------------------------------------------------------------------------
90# Helper function.  DO NOT CALL DIRECTLY.
91function(__check_type_size_impl type var map builtin language)
92  if(NOT CMAKE_REQUIRED_QUIET)
93    message(STATUS "Check size of ${type}")
94  endif()
95
96  # Include header files.
97  set(headers)
98  if(builtin)
99    if(HAVE_SYS_TYPES_H)
100      set(headers "${headers}#include <sys/types.h>\n")
101    endif()
102    if(HAVE_STDINT_H)
103      set(headers "${headers}#include <stdint.h>\n")
104    endif()
105    if(HAVE_STDDEF_H)
106      set(headers "${headers}#include <stddef.h>\n")
107    endif()
108  endif()
109  foreach(h ${CMAKE_EXTRA_INCLUDE_FILES})
110    set(headers "${headers}#include \"${h}\"\n")
111  endforeach()
112
113  # Perform the check.
114
115  if("${language}" STREQUAL "C")
116    set(src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckTypeSize/${var}.c)
117  elseif("${language}" STREQUAL "CXX")
118    set(src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckTypeSize/${var}.cpp)
119  else()
120    message(FATAL_ERROR "Unknown language:\n  ${language}\nSupported languages: C, CXX.\n")
121  endif()
122  set(bin ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckTypeSize/${var}.bin)
123  configure_file(${__check_type_size_dir}/CheckTypeSize.c.in ${src} @ONLY)
124  try_run(${var}_run_result HAVE_${var} ${CMAKE_BINARY_DIR} ${src}
125    COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
126    LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}
127    CMAKE_FLAGS
128      "-DCOMPILE_DEFINITIONS:STRING=${CMAKE_REQUIRED_FLAGS}"
129      "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}"
130    RUN_OUTPUT_VARIABLE ${var}_run_output
131    COMPILE_OUTPUT_VARIABLE output
132    )
133
134  if(${HAVE_${var}} AND NOT "${${var}_run_result}" STREQUAL "FAILED_TO_RUN")
135    set(${var} ${${var}_run_result})
136    if(NOT CMAKE_REQUIRED_QUIET)
137      message(STATUS "Check size of ${type} - done")
138    endif()
139    file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
140      "Determining size of ${type} passed with the following output:\n${output}\n\n")
141    set(${var} "${${var}}" CACHE INTERNAL "CHECK_TYPE_SIZE: sizeof(${type})")
142  else()
143    # The check failed to compile.
144    if(NOT CMAKE_REQUIRED_QUIET)
145      message(STATUS "Check size of ${type} - failed")
146    endif()
147    file(READ ${src} content)
148    file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
149      "Determining size of ${type} failed with the following output:\n${output}\n${src}:\n${content}\n\n")
150    set(${var} "" CACHE INTERNAL "CHECK_TYPE_SIZE: ${type} unknown")
151    file(REMOVE ${map})
152  endif()
153endfunction()
154
155#-----------------------------------------------------------------------------
156macro(CHECK_TYPE_SIZE TYPE VARIABLE)
157  # parse arguments
158  unset(doing)
159  foreach(arg ${ARGN})
160    if("x${arg}" STREQUAL "xBUILTIN_TYPES_ONLY")
161      set(_CHECK_TYPE_SIZE_${arg} 1)
162      unset(doing)
163    elseif("x${arg}" STREQUAL "xLANGUAGE") # change to MATCHES for more keys
164      set(doing "${arg}")
165      set(_CHECK_TYPE_SIZE_${doing} "")
166    elseif("x${doing}" STREQUAL "xLANGUAGE")
167      set(_CHECK_TYPE_SIZE_${doing} "${arg}")
168      unset(doing)
169    else()
170      message(FATAL_ERROR "Unknown argument:\n  ${arg}\n")
171    endif()
172  endforeach()
173  if("x${doing}" MATCHES "^x(LANGUAGE)$")
174    message(FATAL_ERROR "Missing argument:\n  ${doing} arguments requires a value\n")
175  endif()
176  if(DEFINED _CHECK_TYPE_SIZE_LANGUAGE)
177    if(NOT "x${_CHECK_TYPE_SIZE_LANGUAGE}" MATCHES "^x(C|CXX)$")
178      message(FATAL_ERROR "Unknown language:\n  ${_CHECK_TYPE_SIZE_LANGUAGE}.\nSupported languages: C, CXX.\n")
179    endif()
180    set(_language ${_CHECK_TYPE_SIZE_LANGUAGE})
181  else()
182    set(_language C)
183  endif()
184
185  # Optionally check for standard headers.
186  if(_CHECK_TYPE_SIZE_BUILTIN_TYPES_ONLY)
187    set(_builtin 0)
188  else()
189    set(_builtin 1)
190    if("${_language}" STREQUAL "C")
191      check_include_file(sys/types.h HAVE_SYS_TYPES_H)
192      check_include_file(stdint.h HAVE_STDINT_H)
193      check_include_file(stddef.h HAVE_STDDEF_H)
194    elseif("${_language}" STREQUAL "CXX")
195      check_include_file_cxx(sys/types.h HAVE_SYS_TYPES_H)
196      check_include_file_cxx(stdint.h HAVE_STDINT_H)
197      check_include_file_cxx(stddef.h HAVE_STDDEF_H)
198    endif()
199  endif()
200  unset(_CHECK_TYPE_SIZE_BUILTIN_TYPES_ONLY)
201  unset(_CHECK_TYPE_SIZE_LANGUAGE)
202
203  # Compute or load the size or size map.
204  set(${VARIABLE}_KEYS)
205  set(_map_file ${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CheckTypeSize/${VARIABLE}.cmake)
206  if(NOT DEFINED HAVE_${VARIABLE})
207    __check_type_size_impl(${TYPE} ${VARIABLE} ${_map_file} ${_builtin} ${_language})
208  endif()
209  include(${_map_file} OPTIONAL)
210  set(_map_file)
211  set(_builtin)
212
213  # Create preprocessor code.
214  if(${VARIABLE}_KEYS)
215    set(${VARIABLE}_CODE)
216    set(_if if)
217    foreach(key ${${VARIABLE}_KEYS})
218      set(${VARIABLE}_CODE "${${VARIABLE}_CODE}#${_if} defined(${key})\n# define ${VARIABLE} ${${VARIABLE}-${key}}\n")
219      set(_if elif)
220    endforeach()
221    set(${VARIABLE}_CODE "${${VARIABLE}_CODE}#else\n# error ${VARIABLE} unknown\n#endif")
222    set(_if)
223  elseif(${VARIABLE})
224    set(${VARIABLE}_CODE "#define ${VARIABLE} ${${VARIABLE}}")
225  else()
226    set(${VARIABLE}_CODE "/* #undef ${VARIABLE} */")
227  endif()
228endmacro()
229
230#-----------------------------------------------------------------------------
231cmake_policy(POP)
232