交叉编译C++树莓派标准错误

Posted

技术标签:

【中文标题】交叉编译C++树莓派标准错误【英文标题】:Cross compile c++ for raspberry pi std error 【发布时间】:2014-07-07 08:05:04 【问题描述】:

我需要为 Raspberry Pi (armV6) 交叉编译 C/C++ 代码。我按照http://hertaville.com/2012/09/28/development-environment-raspberry-pi-cross-compiler/ 上的说明操作,我的主机(Ubuntu 14.04)上的构建工作正常。

因此,在对所需的库有些不满之后,我的项目在我的主机上构建,我很高兴。但是当我将程序转移到我的树莓派时,我得到了以下错误:

ProjectName: /usr/lib/arm-linux-gnueabihf/libstdc++.so.6: version `GLIBCXX_3.4.18' not found (required by ProjectName)
ProjectName: /usr/lib/arm-linux-gnueabihf/libstdc++.so.6: version `GLIBCXX_3.4.19' not found (required by ProjectName)

所以我怀疑交叉编译器使用的是我主机的 libstd++.so,而不是交叉编译器的一部分,但我不知道如何修复它。

我正在使用 gcc-linaro-arm-linux-gnueabihf-raspbian/arm-linux-gnueabihf-g++ 交叉编译器。

我尝试运行的程序是由其他人直接在 pi 上编写的,它在那里构建、编译和运行完美。

我的 makefile 如下所示:

CC=arm-linux-gnueabihf-g++
IFLAGS=-pthread -I./headers -lwiringPi -lortp -llinphone 
LIBB = -I/home/david/rpi/rootfs/usr/lib/arm-linux-gnueabihf/
CFLAGS=-Wall -std=c++0x
LDFLAGS=-Wall
SOURCES=$(wildcard src/*cpp)
OBJECTS=$(addprefix obj/,$(notdir $(SOURCES:.cpp=.o)))
EXECUTABLE=bin/wackytalky

all: $(SOURCES) LINK_EXEC

debug: CFLAGS += -g
debug: $(SOURCES) LINK_EXEC

LINK_EXEC: $(OBJECTS)
    $(CC) $(LDFLAGS) -o $(EXECUTABLE) $^ $(LIBB) $(IFLAGS)

obj/%.o: src/%.cpp
    $(CC) $(CFLAGS) -o $@ -c $< $(IFLAGS)

clean:
    rm $(EXECUTABLE) obj/*.o

【问题讨论】:

【参考方案1】:

我昨天遇到了和你一样的问题。我还没有时间跟进 Pi 方面,所以我只是修改了我的交叉编译选项(我使用 eclipse)并在链接器命令中添加了-static-libstdc++。这会在 Ubuntu 端静态链接代码,因此不会出现 .so 在 Pi 端的问题。

显然它会生成一个更大的可执行文件。

【讨论】:

不是那么明显:如果您只用这种方式构建一个非常特殊的应用程序,那么静态构建的 exec 不必比动态链接的 exec 加上其专用库的总大小大得多。如果这样可以省去获取正确库的麻烦,那么对于更大尺寸的额外存储成本(如果有的话)可能是值得的【参考方案2】:

您必须将 libstdc++ 和其他文件复制到您的 respary pi。如果您使用较新的编译器生成需要较新库的可执行文件,则此库必须存在于目标上。静态链接不是一个有用的选项。只需将新库复制到目标上的适当路径即可。

所以我怀疑交叉编译器使用的是我主机的 libstd++.so,而不是交叉编译器的一部分,但我不知道如何修复它。

不,我不相信。如果您的编译器配置正确,它将使用正确的库。如果它尝试使用您的 x86 库,您不会收到错误版本的消息,因为动态链接器根本无法使用 x86 库。

对于反对者:-): 您可以在目标上拥有多个版本,因此这样做没有问题,有关详细信息,请参阅 ldconfig。您也可以在本地或任何其他路径中毫无问题地拥有该库,为此您可以使用 LD_LIBRARY_PATH。是的,我没有写过你应该删除旧版本。 Linux 不是 Windows,因此添加的库不会破坏系统。 Linux 没有 win 的 dll 地狱之类的问题...

根据您的特殊要求,我使用两种不同的编译器构建一个程序并从 ldd 获取:

gcc 4.9:

linux-vdso.so.1 =>  (0x00007fff4b7fe000)
librt.so.1 => /lib64/librt.so.1 (0x00000030f2200000)
libdl.so.2 => /lib64/libdl.so.2 (0x00000030f1200000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00000030f0e00000)
libstdc++.so.6 => /opt/linux-gnu_4.9-20140105/lib64/libstdc++.so.6 (0x00007fa4aadc4000)
libm.so.6 => /lib64/libm.so.6 (0x00000030f1600000)
libgcc_s.so.1 => /opt/linux-gnu_4.9-20140105/lib64/libgcc_s.so.1 (0x00007fa4aabad000)
libc.so.6 => /lib64/libc.so.6 (0x00000030f0a00000)

gcc 4.8.2:

linux-vdso.so.1 =>  (0x00007fff4b7fe000)
librt.so.1 => /lib64/librt.so.1 (0x00000030f2200000)
libdl.so.2 => /lib64/libdl.so.2 (0x00000030f1200000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00000030f0e00000)
libstdc++.so.6 => /opt/linux-gnu_4.8.2/lib64/libstdc++.so.6 (0x00007fa4aadc4000)
libm.so.6 => /lib64/libm.so.6 (0x00000030f1600000)
libgcc_s.so.1 => /opt/linux-gnu_4.8.2/lib64/libgcc_s.so.1 (0x00007fa4aabad000)
libc.so.6 => /lib64/libc.so.6 (0x00000030f0a00000)

如您所见:一个库一个系统的两个版本,完全没有问题。

有关操作系统上不同库的更多信息请看这里:

How do applications resolve to different versions of shared libraries at run time?

如果它无法在您的系统上运行,请随时再次询问。

【讨论】:

不,您不必将任何库复制到覆盆子。工具链必须与设备上的库匹配。一些工具链(即 Rasbperry 的 Windows 交叉工具链)允许通过将它们从设备复制到构建机器来更新它们的库,但从不反过来。 如果您确实将库从交叉编译环境复制到目标环境,那么您会发现目标上的现有程序可能会停止工作! 如果交叉编译器 sysroot 与目标机器有相同的库,为什么我需要在目标机器上放置新库?交叉编译器的全部意义不就是为了避免库的无休止转移吗? sysroot 不提供 glibcxx!这个 lib 来自 libstdc++,它是 gcc 发行版的一部分。如果您构建了一个支持较新版本库的新编译器,则该库必须存在于您的目标上。这个库根本不在您的目标系统上。这并不意味着替换 libc 或来自内核和内核 c 接口的东西。正如您在我的 ldd 输出中看到的那样,这些库位于 /opt/... 中,它来自我的个人配置。来自操作系统的库被放置在 /lib 或 /usr/lib (也许其他......) 那么只需将 libstdc++.so.6.19 从主机复制到目标机器就可以解决问题了吗?我不需要做一些符号引用?

以上是关于交叉编译C++树莓派标准错误的主要内容,如果未能解决你的问题,请参考以下文章

在树莓派的交叉编译 qt 中构建应用程序时出错

由于交叉编译树莓派,未定义对“Adafruit_GFX 的 vtable”的引用

树莓派交叉编译(PS交叉编译链下载安装带WiringPi库交叉编译)

搭建树莓派交叉编译环境

rust 交叉编译树莓派程序

rust 交叉编译树莓派程序