diff --git a/cmake/Modules/CheckTypeSize.c.in b/cmake/Modules/CheckTypeSize.c.in index ce19444c7e302..fb93073dc824d 100644 --- a/cmake/Modules/CheckTypeSize.c.in +++ b/cmake/Modules/CheckTypeSize.c.in @@ -5,14 +5,24 @@ # define KEY '_','_','i','3','8','6' #elif defined(__x86_64) # define KEY '_','_','x','8','6','_','6','4' -#elif defined(__ppc__) -# define KEY '_','_','p','p','c','_','_' +#elif defined(__PPC64__) +# define KEY '_','_','P','P','C','6','4','_','_' #elif defined(__ppc64__) # define KEY '_','_','p','p','c','6','4','_','_' +#elif defined(__PPC__) +# define KEY '_','_','P','P','C','_','_' +#elif defined(__ppc__) +# define KEY '_','_','p','p','c','_','_' +#elif defined(__aarch64__) +# define KEY '_','_','a','a','r','c','h','6','4','_','_' +#elif defined(__ARM_ARCH_7A__) +# define KEY '_','_','A','R','M','_','A','R','C','H','_','7','A','_','_' +#elif defined(__ARM_ARCH_7S__) +# define KEY '_','_','A','R','M','_','A','R','C','H','_','7','S','_','_' #endif #define SIZE (sizeof(@type@)) -char info_size[] = {'I', 'N', 'F', 'O', ':', 's','i','z','e','[', +static char info_size[] = {'I', 'N', 'F', 'O', ':', 's','i','z','e','[', ('0' + ((SIZE / 10000)%10)), ('0' + ((SIZE / 1000)%10)), ('0' + ((SIZE / 100)%10)), @@ -33,5 +43,5 @@ int main(int argc, char *argv[]) int require = 0; require += info_size[argc]; (void)argv; - return SIZE; + return require; } diff --git a/cmake/Modules/CheckTypeSize.cmake b/cmake/Modules/CheckTypeSize.cmake index e277605977b49..b8bc4d4e65079 100644 --- a/cmake/Modules/CheckTypeSize.cmake +++ b/cmake/Modules/CheckTypeSize.cmake @@ -1,140 +1,200 @@ -#.rst: -# CheckTypeSize -# ------------- -# -# Check sizeof a type -# -# :: -# -# CHECK_TYPE_SIZE(TYPE VARIABLE [BUILTIN_TYPES_ONLY] -# [LANGUAGE ]) -# -# Check if the type exists and determine its size. On return, -# "HAVE_${VARIABLE}" holds the existence of the type, and "${VARIABLE}" -# holds one of the following: -# -# :: -# -# = type has non-zero size -# "0" = type has arch-dependent size (see below) -# "" = type does not exist -# -# Both ``HAVE_${VARIABLE}`` and ``${VARIABLE}`` will be created as internal -# cache variables. -# -# Furthermore, the variable "${VARIABLE}_CODE" holds C preprocessor code -# to define the macro "${VARIABLE}" to the size of the type, or leave -# the macro undefined if the type does not exist. -# -# The variable "${VARIABLE}" may be "0" when CMAKE_OSX_ARCHITECTURES has -# multiple architectures for building OS X universal binaries. This -# indicates that the type size varies across architectures. In this -# case "${VARIABLE}_CODE" contains C preprocessor tests mapping from -# each architecture macro to the corresponding type size. The list of -# architecture macros is stored in "${VARIABLE}_KEYS", and the value for -# each key is stored in "${VARIABLE}-${KEY}". -# -# If the BUILTIN_TYPES_ONLY option is not given, the macro checks for -# headers , , and , and saves results -# in HAVE_SYS_TYPES_H, HAVE_STDINT_H, and HAVE_STDDEF_H. The type size -# check automatically includes the available headers, thus supporting -# checks of types defined in the headers. -# -# If LANGUAGE is set, the specified compiler will be used to perform the -# check. Acceptable values are C and CXX -# -# Despite the name of the macro you may use it to check the size of more -# complex expressions, too. To check e.g. for the size of a struct -# member you can do something like this: -# -# :: -# -# check_type_size("((struct something*)0)->member" SIZEOF_MEMBER) -# -# -# -# The following variables may be set before calling this macro to modify -# the way the check is run: -# -# :: -# -# CMAKE_REQUIRED_FLAGS = string of compile command line flags -# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) -# CMAKE_REQUIRED_INCLUDES = list of include directories -# CMAKE_REQUIRED_LIBRARIES = list of libraries to link -# CMAKE_REQUIRED_QUIET = execute quietly without messages -# CMAKE_EXTRA_INCLUDE_FILES = list of extra headers to include - -#============================================================================= -# Copyright 2002-2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +CheckTypeSize +------------- + +Check sizeof a type + +.. command:: CHECK_TYPE_SIZE + + .. code-block:: cmake + + CHECK_TYPE_SIZE(TYPE VARIABLE [BUILTIN_TYPES_ONLY] + [LANGUAGE ]) + + Check if the type exists and determine its size. On return, + ``HAVE_${VARIABLE}`` holds the existence of the type, and ``${VARIABLE}`` + holds one of the following: + + :: + + = type has non-zero size + "0" = type has arch-dependent size (see below) + "" = type does not exist + + Both ``HAVE_${VARIABLE}`` and ``${VARIABLE}`` will be created as internal + cache variables. + + Furthermore, the variable ``${VARIABLE}_CODE`` holds C preprocessor code + to define the macro ``${VARIABLE}`` to the size of the type, or leave + the macro undefined if the type does not exist. + + The variable ``${VARIABLE}`` may be ``0`` when + :variable:`CMAKE_OSX_ARCHITECTURES` has multiple architectures for building + OS X universal binaries. This indicates that the type size varies across + architectures. In this case ``${VARIABLE}_CODE`` contains C preprocessor + tests mapping from each architecture macro to the corresponding type size. + The list of architecture macros is stored in ``${VARIABLE}_KEYS``, and the + value for each key is stored in ``${VARIABLE}-${KEY}``. + + If the ``BUILTIN_TYPES_ONLY`` option is not given, the macro checks for + headers ````, ````, and ````, and saves + results in ``HAVE_SYS_TYPES_H``, ``HAVE_STDINT_H``, and ``HAVE_STDDEF_H``. + The type size check automatically includes the available headers, thus + supporting checks of types defined in the headers. + + If ``LANGUAGE`` is set, the specified compiler will be used to perform the + check. Acceptable values are ``C`` and ``CXX``. + +Despite the name of the macro you may use it to check the size of more +complex expressions, too. To check e.g. for the size of a struct +member you can do something like this: + +.. code-block:: cmake + + check_type_size("((struct something*)0)->member" SIZEOF_MEMBER) + + +The following variables may be set before calling this macro to modify +the way the check is run: + +``CMAKE_REQUIRED_FLAGS`` + string of compile command line flags. +``CMAKE_REQUIRED_DEFINITIONS`` + list of macros to define (-DFOO=bar). +``CMAKE_REQUIRED_INCLUDES`` + list of include directories. +``CMAKE_REQUIRED_LINK_OPTIONS`` + .. versionadded:: 3.14 + list of options to pass to link command. +``CMAKE_REQUIRED_LIBRARIES`` + list of libraries to link. +``CMAKE_REQUIRED_QUIET`` + .. versionadded:: 3.1 + execute quietly without messages. +``CMAKE_EXTRA_INCLUDE_FILES`` + list of extra headers to include. +#]=======================================================================] include(CheckIncludeFile) include(CheckIncludeFileCXX) -cmake_policy(PUSH) -cmake_policy(VERSION 3.0) - get_filename_component(__check_type_size_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) +include_guard(GLOBAL) + +cmake_policy(PUSH) +cmake_policy(SET CMP0054 NEW) + #----------------------------------------------------------------------------- # Helper function. DO NOT CALL DIRECTLY. function(__check_type_size_impl type var map builtin language) if(NOT CMAKE_REQUIRED_QUIET) - message(STATUS "Check size of ${type}") + message(CHECK_START "Check size of ${type}") + endif() + + # Perform language check + if(language STREQUAL "C") + set(src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckTypeSize/${var}.c) + elseif(language STREQUAL "CXX") + set(src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckTypeSize/${var}.cpp) + else() + message(FATAL_ERROR "Unknown language:\n ${language}\nSupported languages: C, CXX.\n") endif() # Include header files. set(headers) if(builtin) - if(HAVE_SYS_TYPES_H) - set(headers "${headers}#include \n") - endif() - if(HAVE_STDINT_H) - set(headers "${headers}#include \n") - endif() - if(HAVE_STDDEF_H) - set(headers "${headers}#include \n") + if(language STREQUAL "CXX" AND type MATCHES "^std::") + if(HAVE_SYS_TYPES_H) + string(APPEND headers "#include \n") + endif() + if(HAVE_CSTDINT) + string(APPEND headers "#include \n") + endif() + if(HAVE_CSTDDEF) + string(APPEND headers "#include \n") + endif() + else() + if(HAVE_SYS_TYPES_H) + string(APPEND headers "#include \n") + endif() + if(HAVE_STDINT_H) + string(APPEND headers "#include \n") + endif() + if(HAVE_STDDEF_H) + string(APPEND headers "#include \n") + endif() endif() endif() foreach(h ${CMAKE_EXTRA_INCLUDE_FILES}) - set(headers "${headers}#include \"${h}\"\n") + string(APPEND headers "#include \"${h}\"\n") endforeach() # Perform the check. - - if("${language}" STREQUAL "C") - set(src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckTypeSize/${var}.c) - elseif("${language}" STREQUAL "CXX") - set(src ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckTypeSize/${var}.cpp) - else() - message(FATAL_ERROR "Unknown language:\n ${language}\nSupported languages: C, CXX.\n") - endif() set(bin ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckTypeSize/${var}.bin) configure_file(${__check_type_size_dir}/CheckTypeSize.c.in ${src} @ONLY) - try_run(${var}_run_result HAVE_${var} ${CMAKE_BINARY_DIR} ${src} + try_compile(HAVE_${var} ${CMAKE_BINARY_DIR} ${src} COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + # XXX: Emscripten: Add --oformat=wasm to ensure the output binary is that + # wasm file itself, and we can run `strings` on it to find the static data. + LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS} "--oformat=wasm" "-sWASM=1" LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${CMAKE_REQUIRED_FLAGS}" "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}" - RUN_OUTPUT_VARIABLE ${var}_run_output - COMPILE_OUTPUT_VARIABLE output + OUTPUT_VARIABLE output + COPY_FILE ${bin} ) - if(${HAVE_${var}} AND NOT "${${var}_run_result}" STREQUAL "FAILED_TO_RUN") - set(${var} ${${var}_run_result}) + if(HAVE_${var}) + # The check compiled. Load information from the binary. + file(STRINGS ${bin} strings LIMIT_COUNT 10 REGEX "INFO:size") + + # Parse the information strings. + set(regex_size ".*INFO:size\\[0*([^]]*)\\].*") + set(regex_key " key\\[([^]]*)\\]") + set(keys) + set(code) + set(mismatch) + set(first 1) + foreach(info ${strings}) + if("${info}" MATCHES "${regex_size}") + # Get the type size. + set(size "${CMAKE_MATCH_1}") + if(first) + set(${var} ${size}) + elseif(NOT "${size}" STREQUAL "${${var}}") + set(mismatch 1) + endif() + set(first 0) + + # Get the architecture map key. + string(REGEX MATCH "${regex_key}" key "${info}") + string(REGEX REPLACE "${regex_key}" "\\1" key "${key}") + if(key) + string(APPEND code "\nset(${var}-${key} \"${size}\")") + list(APPEND keys ${key}) + endif() + endif() + endforeach() + + # Update the architecture-to-size map. + if(mismatch AND keys) + configure_file(${__check_type_size_dir}/CheckTypeSizeMap.cmake.in ${map} @ONLY) + set(${var} 0) + else() + file(REMOVE ${map}) + endif() + + if(mismatch AND NOT keys) + 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 !") + endif() + if(NOT CMAKE_REQUIRED_QUIET) - message(STATUS "Check size of ${type} - done") + message(CHECK_PASS "done") endif() file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log "Determining size of ${type} passed with the following output:\n${output}\n\n") @@ -142,7 +202,7 @@ function(__check_type_size_impl type var map builtin language) else() # The check failed to compile. if(NOT CMAKE_REQUIRED_QUIET) - message(STATUS "Check size of ${type} - failed") + message(CHECK_FAIL "failed") endif() file(READ ${src} content) file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log @@ -187,14 +247,19 @@ macro(CHECK_TYPE_SIZE TYPE VARIABLE) set(_builtin 0) else() set(_builtin 1) - if("${_language}" STREQUAL "C") + if(_language STREQUAL "C") check_include_file(sys/types.h HAVE_SYS_TYPES_H) check_include_file(stdint.h HAVE_STDINT_H) check_include_file(stddef.h HAVE_STDDEF_H) - elseif("${_language}" STREQUAL "CXX") + elseif(_language STREQUAL "CXX") check_include_file_cxx(sys/types.h HAVE_SYS_TYPES_H) - check_include_file_cxx(stdint.h HAVE_STDINT_H) - check_include_file_cxx(stddef.h HAVE_STDDEF_H) + if("${TYPE}" MATCHES "^std::") + check_include_file_cxx(cstdint HAVE_CSTDINT) + check_include_file_cxx(cstddef HAVE_CSTDDEF) + else() + check_include_file_cxx(stdint.h HAVE_STDINT_H) + check_include_file_cxx(stddef.h HAVE_STDDEF_H) + endif() endif() endif() unset(_CHECK_TYPE_SIZE_BUILTIN_TYPES_ONLY) @@ -215,10 +280,10 @@ macro(CHECK_TYPE_SIZE TYPE VARIABLE) set(${VARIABLE}_CODE) set(_if if) foreach(key ${${VARIABLE}_KEYS}) - set(${VARIABLE}_CODE "${${VARIABLE}_CODE}#${_if} defined(${key})\n# define ${VARIABLE} ${${VARIABLE}-${key}}\n") + string(APPEND ${VARIABLE}_CODE "#${_if} defined(${key})\n# define ${VARIABLE} ${${VARIABLE}-${key}}\n") set(_if elif) endforeach() - set(${VARIABLE}_CODE "${${VARIABLE}_CODE}#else\n# error ${VARIABLE} unknown\n#endif") + string(APPEND ${VARIABLE}_CODE "#else\n# error ${VARIABLE} unknown\n#endif") set(_if) elseif(${VARIABLE}) set(${VARIABLE}_CODE "#define ${VARIABLE} ${${VARIABLE}}") diff --git a/test/cmake/check_type_size/CMakeLists.txt b/test/cmake/check_type_size/CMakeLists.txt new file mode 100644 index 0000000000000..9a1bf50eb6a9e --- /dev/null +++ b/test/cmake/check_type_size/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.0) + +project(test_cmake) + +include(CheckTypeSize) + +check_type_size("int" int_size) +if (NOT "${int_size}" EQUAL "4") + message(FATAL_ERROR "CHECK_TYPE_SIZE with int did not return 4! (${int_size})") +endif() +message(STATUS "CHECK_TYPE_SIZE int -> ${int_size}") + +check_type_size("int[256+1]" big_size) +if (NOT "${big_size}" EQUAL "1028") + message(FATAL_ERROR "CHECK_TYPE_SIZE with int[256+1] did not return 1028! (${big_size})") +endif() +message(STATUS "CHECK_TYPE_SIZE int -> ${big_size}") diff --git a/test/cmake/target_js/CMakeLists.txt b/test/cmake/target_js/CMakeLists.txt index 5df75708a12c3..916b7a40de44d 100644 --- a/test/cmake/target_js/CMakeLists.txt +++ b/test/cmake/target_js/CMakeLists.txt @@ -79,16 +79,7 @@ endif() include(TestBigEndian) test_big_endian(endian_result) if (NOT ${endian_result} EQUAL 0) - message(FATAL_ERROR "TEST_BIG_ENDIAN did not return 0!") -endif() - -# Requires CMAKE_CROSSCOMPILING_EMULATOR support. -if (${CMAKE_VERSION} VERSION_GREATER 3.2.20150502) - include(CheckTypeSize) - check_type_size("int" int_size) - if (NOT ${int_size} EQUAL 4) - message(FATAL_ERROR "CHECK_TYPE_SIZE with int did not return 4!") - endif() + message(FATAL_ERROR "TEST_BIG_ENDIAN did not return 0!") endif() add_executable(test_cmake ${sourceFiles}) diff --git a/test/test_other.py b/test/test_other.py index b62f9576619f7..b2e45cd56e5a9 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -890,6 +890,9 @@ def test_pkg_config_packages(self): out = self.run_process([emmake, 'pkg-config', '--modversion', package], stdout=PIPE).stdout self.assertContained(version, out) + def test_cmake_check_type_size(self): + self.run_process([EMCMAKE, 'cmake', test_file('cmake/check_type_size')]) + def test_system_include_paths(self): # Verify that all default include paths are within `emscripten/system`