【问题标题】:Interrogate the C compiler about data types when cross-compiling交叉编译时向 C 编译器询问数据类型
【发布时间】:2020-01-18 16:10:10
【问题描述】:

我正在开发一个使用 GNU Autotools 构建系统的跨平台项目,我想知道是否有办法运行一个简单的 sizeof(int) 并将结果传递给 configure 脚本(甚至简单到标准输出)交叉编译时

假设我正在使用 32 位机器为 64 位机器编译程序。如果我的编译器能够为不同的架构编译代码,这意味着肯定知道sizeof(int) 在目标架构上的结果。

我的问题是:我如何在交叉编译时询问编译器以获得该信息?

编辑

正如 Ian Abbott 在 cmets 中解释的那样,Autoconf Archive 中有一个 AX_COMPILE_CHECK_SIZEOF() 宏能够计算 sizeof() 通过编译检查(不是运行检查),因此在交叉时可以工作-编译。不幸的是,宏无法处理包含非字母数字字符的表达式(例如,sizeof(sizeof(char)),其中sizeof(char) 包含圆括号),因此I have published 是它的一个分支,可以选择允许给出字母数字“标签”到检查,用作有效的变量名:

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() 将在 configure 脚本中导出一个名为 ${ac_cv_sizeof_size_t} 的 shell 变量,并在 C 环境中导出一个名为 SIZEOF_SIZE_T 的预处理器宏,两者都包含 sizeof(sizeof(char)) 的扩展。

Autoconf 的原生 AC_CHECK_SIZEOF()

正如 Brett 在 cmets 中指出的那样,有一个原生的 AC_CHECK_SIZEOF() 宏,它显然不会像 AX_COMPILE_CHECK_SIZEOF() 那样将计算大小限制为 2 的幂(加上手动提供的大小) .不幸的是,经过快速检查后,我发现AC_CHECK_SIZEOF() 也不允许将sizeof(char) 作为参数传递(如果我尝试,我会得到error: AC_CHECK_SIZEOF: requires literal arguments - 如果我通过写@ 使用Autoconf's quadrigraphs 也会发生同样的情况987654351@).

附录 - 交叉编译时计算CHAR_BIT

这有点离题,但因为我需要它,Autoconf Archive 的 AX_COMPILE_CHECK_SIZEOF() 宏启发我编写了一个 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(不带参数)后,configure 脚本中提供了一个名为 ${ac_cv_char_bit} 的 shell 变量,C 环境中提供了一个名为 COMPUTED_CHAR_BIT 的预处理器宏,两者都包含大小char 数据类型以位为单位。

【问题讨论】:

  • 即使在 64 位机器上,我也希望 int 是 32 位的。你使用的是哪个平台,int 是 64 位的?
  • 如果您正在编写跨平台代码,您可能希望声明变量并编写代码,使其尽可能独立于 32 位或 64 位机器。例如,如果您需要一个最多为 32 位的整数,那么您可以使用 int 而无需检查架构是什么。如果您需要 64 位,则在任一平台上使用保证 64 位的类型(例如long long int)。
  • 您可以尝试Autoconf Archive 中的ax_compile_check_sizeof 宏。它进行编译时检查,因此在交叉编译时应该可以工作。
  • sizeof(sizeof(char)) 的表达式也产生size_t 的大小(sizeof 运算符总是返回size_t 类型的值),不需要GNU C 关键字typeof。即使将[sizeof(char)] 传递给宏乍一看似乎是错误的。
  • AC_CHECK_SIZEOF 宏适用于交叉编译。它有效地执行了“负大小”数组技巧,并使用二进制搜索来收敛到正确的值。

标签: c gcc cross-compiling configure autotools


【解决方案1】:

如果您真的在使用 GCC(如已标记),请转储预定义的预处理器宏并查找您关心的类型。例如:

$ 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

【讨论】:

  • Carl,这是个好方法,谢谢。我最终使用/破解了 Ian Abbott 建议的 M4 宏,因为我认为在 sizeof() 不正确时反复检查编译器是否失败是一种比使用正则表达式更通用和可靠的方法,但这可以工作也是。
  • 为什么要依赖正则表达式呢?如果要假设 gcc 并使用预定义的宏,那么获取值的自然方法是使用预处理器来扩展感兴趣的宏。搜索“SIZE”只是帮助您提前确定要探测的宏。
  • 我并不是说你必须使用 grep。我这样做只是为了展示其中一些以供参考。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多