Опросить компилятор C о типах данных при кросс-компиляции - PullRequest
1 голос
/ 18 января 2020

Я работаю над кроссплатформенным проектом, который использует GNU Autotools для системы сборки, и мне было интересно, есть ли способ запустить простой sizeof(int) и передать результат в сценарий configure (или даже просто к стандартному выводу) при кросс-компиляции .

Давайте представим, что я использую 32-битную машину для компиляции программы для 64-битной машины. Если мой компилятор может компилировать код для другой архитектуры, это означает, что он наверняка знает результат sizeof(int) на целевой архитектуре .

Мой вопрос: как запросить компилятор для получения этой информации при кросс-компиляции?

EDIT

Как пояснил Ян Эбботт в комментариях, в Autoconf есть макрос AX_COMPILE_CHECK_SIZEOF() Архив способен вычислять sizeof() с помощью проверок компиляции (не проверок выполнения), что, следовательно, работает при кросс-компиляции. К сожалению, макрос не может работать с выражениями, которые содержат не-алфавитные символы c (например, sizeof(sizeof(char)), где sizeof(char) содержит круглые скобки), поэтому я опубликовал a fork опционально, что позволяет присваивать чекам alphanumeri c «меток» для использования в качестве допустимых имен переменных:

dnl  NA_SANITIZE_VARNAME(string)
dnl  **************************************************************************
dnl
dnl  Replaces `/\W/g,` with `'_'` and `/^\d/` with `_\0`
dnl
dnl  From: not-autotools/m4/not-autotools.m4
dnl
dnl  **************************************************************************
AC_DEFUN([NA_SANITIZE_VARNAME],
    [m4_if(m4_bregexp(m4_normalize([$1]), [[0-9]]), [0], [_])[]m4_translit(m4_normalize([$1]),
        [ !"#$%&\'()*+,-./:;<=>?@[\\]^`{|}~],
        [__________________________________])])


dnl  NC_CC_CHECK_SIZEOF(data-type[, headers[, store-as[, extra-sizes]]])
dnl  **************************************************************************
dnl
dnl  Checks for the size of `data-type` using **compile checks**, not run
dnl  checks.
dnl
dnl  From: https://github.com/madmurphy/not-autotools/blob/master/m4/not-cc.m4
dnl
dnl  **************************************************************************
AC_DEFUN([NC_CC_CHECK_SIZEOF], [
    m4_pushdef([__label__],
        NA_SANITIZE_VARNAME([sizeof_]m4_tolower(m4_ifblank([$3],
            [[$1]], [[$3]]))))
    AC_MSG_CHECKING([size of `$1`])
    AC_CACHE_VAL([ac_cv_]__label__, [
        # List sizes in rough order of prevalence.
        for nc_sizeof in 4 8 1 2 16 m4_normalize([$4]) ; do
            AC_COMPILE_IFELSE([
                AC_LANG_PROGRAM([[$2]], [[
                    switch (0) {
                        case 0:
                        case (sizeof ($1) ==
                            ${nc_sizeof}):;
                    }
                ]])
            ],
                [AS_VAR_COPY([ac_cv_]__label__, [nc_sizeof])])
            AS_IF([test "x${ac_cv_]__label__[}" != x], [break;])
        done
    ])
    AS_IF([test "x${ac_cv_]__label__[}" = x], [
        AC_MSG_RESULT([??])
        AC_MSG_ERROR([cannot determine a size for $1])
    ])
    AC_MSG_RESULT([${ac_cv_]__label__[}])
    AC_DEFINE_UNQUOTED(m4_toupper(m4_quote(__label__)),
        [${ac_cv_]__label__[}],
        [The number of bytes in type $1])
    m4_ifnblank([$3],
        [AS_VAR_COPY([na_]m4_quote(m4_tolower([$3])), [nc_sizeof])])
    m4_popdef([__label__])
])

В этой версии мы можем использовать, например, метку size_t для выражения sizeof(sizeof(char)):

NC_CC_CHECK_SIZEOF([sizeof(char)], [], [size_t])

При этом NC_CC_CHECK_SIZEOF() экспортирует переменную оболочки с именем ${ac_cv_sizeof_size_t} в сценарии configure и макрос препроцессора с именем SIZEOF_SIZE_T в C окружение, оба содержат расширение sizeof(sizeof(char)).

нативный Autoconf AC_CHECK_SIZEOF() макрос

Как указал Бретт в комментариях, есть нативный AC_CHECK_SIZEOF()* Макрос 1048 *, который явно не ограничивает вычисляемый размер степенями 2 (плюс предоставленные вручную размеры), как AX_COMPILE_CHECK_SIZEOF(). К сожалению, после быстрой проверки я обнаружил, что AC_CHECK_SIZEOF() также не позволяет передавать sizeof(char) в качестве аргумента (если я пытаюсь получить, я получаю error: AC_CHECK_SIZEOF: requires literal arguments - то же самое происходит, если я использую квадриграфы Autoconf , написав AC_CHECK_SIZEOF([sizeof@{:@char@:}@])).

Приложение - вычисление CHAR_BIT при кросс-компиляции

Это немного не в порядке c, но, так как я нуждался в этом, Autoconf Archive's * Макрос 1063 * вдохновил меня на написание макроса M4, который вычисляет CHAR_BIT при кросс-компиляции (для работы макроса не требуется limits.h):

dnl  NC_CC_CHECK_CHAR_BIT
dnl  **************************************************************************
dnl
dnl  Calculates the size in bits of the `char` data type using compile checks
dnl
dnl  From: https://github.com/madmurphy/not-autotools/blob/master/m4/not-cc.m4
dnl
dnl  **************************************************************************
AC_DEFUN([NC_CC_CHECK_CHAR_BIT], [
    AC_MSG_CHECKING([size of `char` in bits])
    AC_CACHE_VAL([ac_cv_char_bit], [
        # Minimum size in bits for `char` is guaranteed to be 8
        for nc_char_bit in {8..64}; do
            AC_COMPILE_IFELSE([
                AC_LANG_PROGRAM(, [[
                    switch (0) {
                        case 0: case ((unsigned char)
                        (1 << ${nc_char_bit})):;
                    }
                ]])
            ], [], [break])
        done
        AS_VAR_COPY([ac_cv_char_bit], [nc_char_bit])
    ])
    AC_MSG_RESULT([${ac_cv_char_bit}])
    AC_DEFINE_UNQUOTED([COMPUTED_CHAR_BIT],
        [${ac_cv_char_bit}],
        [The number of bits in `char`])
])

После вызова NC_CC_CHECK_CHAR_BIT (без аргументов) переменная оболочки с именем ${ac_cv_char_bit} становится доступной в сценарии configure, а макрос препроцессора с именем COMPUTED_CHAR_BIT становится доступным в среде C, причем оба содержат размер типа данных char, измеряемый в битах.

1 Ответ

3 голосов
/ 18 января 2020

Если вы действительно используете G CC (как помечено), сбросьте предопределенные макросы препроцессора и найдите нужные вам типы. Например:

$ gcc -x c -E -dM /dev/null | grep SIZE
#define __SIZEOF_FLOAT80__ 16
#define __SIZE_MAX__ 0xffffffffffffffffUL
#define __SIZEOF_INT__ 4
#define __SIZEOF_POINTER__ 8
#define __SIZEOF_LONG__ 8
#define __SIZEOF_LONG_DOUBLE__ 16
#define __SIZEOF_SIZE_T__ 8
#define __SIZEOF_WINT_T__ 4
#define __SIZE_TYPE__ long unsigned int
#define __SIZEOF_PTRDIFF_T__ 8
#define __SIZE_WIDTH__ 64
#define __SIZEOF_FLOAT__ 4
#define __SIZEOF_FLOAT128__ 16
#define __SIZEOF_SHORT__ 2
#define __SIZEOF_INT128__ 16
#define __SIZEOF_WCHAR_T__ 4
#define __SIZEOF_DOUBLE__ 8
#define __SIZEOF_LONG_LONG__ 8

32-битный пример:

$ gcc -m32 -x c -E -dM /dev/null | grep SIZE
#define __SIZEOF_FLOAT80__ 16
#define __SIZE_MAX__ 0xffffffffUL
#define __SIZEOF_INT__ 4
#define __SIZEOF_POINTER__ 4
#define __SIZEOF_LONG__ 4
#define __SIZEOF_LONG_DOUBLE__ 16
#define __SIZEOF_SIZE_T__ 4
#define __SIZEOF_WINT_T__ 4
#define __SIZE_TYPE__ long unsigned int
#define __SIZEOF_PTRDIFF_T__ 4
#define __SIZE_WIDTH__ 32
#define __SIZEOF_FLOAT__ 4
#define __SIZEOF_FLOAT128__ 16
#define __SIZEOF_SHORT__ 2
#define __SIZEOF_WCHAR_T__ 4
#define __SIZEOF_DOUBLE__ 8
#define __SIZEOF_LONG_LONG__ 8
...