在armhf上没有__fpclassify的实现。

3
我正在使用ARM的10.3-2021.07 GCC 工具链(具体来说是this文件未压缩到ARMGCC中)为Raspberry Pi 4B进行交叉编译。同时,我还使用最新的Raspberry OS image作为sysroot(通过loop-mounted挂载到RPISYSROOT)。主机是运行在Windows主机上的Ubuntu Xenial虚拟机。
当使用以下编译行(为了易读性而编辑,CFLAGS 受树莓派的 /proc/cpuinfoGentooGNU 的启发)时:
${ARMGCC}/bin/arm-none-linux-gnueabihf-g++ -std=c++11 \
-v -w -fexceptions -fpermissive --sysroot=$RPISYSROOT \
-pipe -mcpu=cortex-a72 -mfpu=neon-vfpv4 -mfloat-abi=hard -g \
-I . -I .. -I libA/include -I libB/include \
-I ${ARMGCC}/arm-none-linux-gnueabihf/libc/usr/include \
-I ${RPISYSROOT}/usr/include/arm-linux-gnueabihf \
-c file.cpp -o obj/debug/file.o

我遇到了以下错误:
$ARMGCC/arm-none-linux-gnueabihf/libc/usr/include/bits/mathcalls-helper-functions.h:20:24: error: ‘__fpclassify’ has not been declared
   20 | __MATHDECL_ALIAS (int, __fpclassify,, (_Mdouble_ __value), fpclassify)
      |                        ^~~~~~~~~~~~

我看到在ARMGCCRPISYSROOT和Raspberry Pi的tools git仓库中都有使用__fpclassify,它们似乎都是同一文件的不同版本:

usr/include/math.h
usr/include/bits/mathcalls-helper-functions.h

路径可能略有不同。然而,这些都没有提供__fpclassify的声明或实现。这似乎来自libm,我想它已经成为libc的一部分了。我已经在RPISYSROOT上安装了libc
我找到的唯一实现是来自uCLibc,但我不认为混合使用libc实现是个好主意。

另外,由于树莓派是armhf架构,我应该看到这些错误吗?


如果是由libm提供的,您可能需要在命令中使用-lm进行链接。 - msbit
1个回答

1
这里的问题是混合了两组头文件,一组是构建链(ARMGCC),另一组是指定系统根目录(RPISYSROOT)的头文件。特别地,假设有一个类似于以下代码的file.cpp文件:
#include <cmath>

void function(void) {}

你的编译命令将执行以下嵌套包含:
  • ${ARMGCC}/arm-none-linux-gnueabihf/include/c++/10.3.1/cmath
  • ${RPISYSROOT}/usr/include/math.h
  • ${ARMGCC}/arm-none-linux-gnueabihf/libc/usr/include/bits/mathcalls-helper-functions.h
您收到的特定错误信息(提到__fpclassify)有点误导人,因为此时最相关的未定义内容是__MATHDECL_ALIAS这个函数宏,该宏在${ARMGCC}/arm-none-linux-gnueabihf/libc/usr/include/math.h中定义。
如果您查看RPISYSROOT下的同一文件,您会发现它使用__MATHDECL_1代替:

/* Classify given number.  */
__MATHDECL_1 (int, __fpclassify,, (_Mdouble_ __value))
     __attribute__ ((__const__));

这个函数在${RPISYSROOT}/usr/include/math.h中定义。

所以你需要做的就是确保包含${RPISYSROOT}/usr/include/arm-linux-gnueabihf/bits/mathcalls-helper-functions.h而不是ARMGCC对应的文件,可以通过改变编译命令中包含的顺序来实现。简化编译命令后,我们得到:

${ARMGCC}/bin/arm-none-linux-gnueabihf-g++ \
  --sysroot=${RPISYSROOT} \
  -I ${ARMGCC}/arm-none-linux-gnueabihf/libc/usr/include \
  -I ${RPISYSROOT}/usr/include/arm-linux-gnueabihf \
  -c file.cpp \
  -o obj/debug/file.o

如上所述失败。将其更改为:

${ARMGCC}/bin/arm-none-linux-gnueabihf-g++ \
  --sysroot=${RPISYSROOT} \
  -I ${RPISYSROOT}/usr/include/arm-linux-gnueabihf \
  -I ${ARMGCC}/arm-none-linux-gnueabihf/libc/usr/include \
  -c file.cpp \
  -o obj/debug/file.o

编译成功。

事实上,对于这种情况,我们可以通过以下方式删除对任何 ARMGCC 包含的显式引用:

${ARMGCC}/bin/arm-none-linux-gnueabihf-g++ \
  --sysroot=${RPISYSROOT} \
  -I ${RPISYSROOT}/usr/include/arm-linux-gnueabihf \
  -c file.cpp \
  -o obj/debug/file.o

它还可以编译。


1
我通过使用树莓派的工具链和一个Raspbian系统根解决了这个问题。 - vesperto

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接