嵌入式系统的c++编译问题

斯塔谢克

我有一些关于嵌入式系统编译问题的相关问题。我的问题不仅是关于如何做某事,而是关于为什么,因为我有解决我的问题的方法(但也许有更好的解决方案?),但不知道为什么有些事情在某些条件下有效,而在某些情况下无效其他。我已经在这方面花了一些时间,但直到昨天我还在做一些盲目的事情,反复试验,不知道自己在做什么。是时候停止了!请帮忙。

设想

我想在 Zedboard 上为 Xilinx 的 Zynq ARM 处理器开发一个应用程序。该应用程序将涉及多线程、一些音频操作和 httpserver。所以我需要 pthread、alsa、sndfile 和 microhttpd 库。我用 yocto 创建了 rootfs。在原始 conf.local 文件中,我添加/修改了以下几行:

BB_NUMBER_THREADS ?= "${@oe.utils.cpu_count()}"
PARALLEL_MAKE ?= "-j ${@oe.utils.cpu_count()}"
MACHINE ?= "zedboard-zynq7"
PACKAGE_CLASSES ?= "package_deb"
EXTRA_IMAGE_FEATURES = "debug-tweaks eclipse-debug"
IMAGE_INSTALL_append = "libgcc alsa-utils mpg123 libstdc++ sthttpd libmicrohttpd libsndfile1"
LICENSE_FLAGS_WHITELIST = "commercial_mpg123"

我还必须向 bblayers.conf 添加一些额外的层(当然也下载了它们):

meta-xilinx
meta-multimedia (from meta-openembedded)
meta-oe         (from meta-openembedded)
meta-webserver  (from meta-openembedded)

最后,我用 bitbake 生成了 core-image-minimal。

这与 Linux 内核和其他单独编译的东西一起启动并运行良好。

问题

1. 带有这个 rootfs 的简单应用

它是 Zynq 的应用程序,所以我使用 XSDK,它是 Xilinx 的 SDK,基于 Eclipse。我创建了新的应用程序项目。在对话窗口中,我选择 Linux 作为平台,C++ 作为语言,并提供了我解压后的 rootfs 的路径(正是系统通过 NFS 引导的那个)。我的rootfs路径是/home/stas/ZedboardPetalinuxFS(不是Petalinux,我刚用过,这个文件夹名还是一样)。这为 rootfs 中的库和头文件搜索设置了正确的路径。我从一些非常简单的事情开始:

#include <pthread.h>

int main()
{
    int i;
    i = 1;
    return 0;
}

我还为链接器添加了 pthread 库(在 Eclipse 设置中)。此时的链接命令:

arm-linux-gnueabihf-g++ -L"/home/stas/ZedboardPetalinuxFS/usr/lib" -L"/home/stas/ZedboardPetalinuxFS/lib" -o "test.elf"  ./src/main.o   -lpthread

此时它编译。但是它停止了,当我添加 sndfile 库时

#include <sndfile.h>

这是合理的,因为这个 rootfs 没有所有的头文件。我需要添加另一个路径来搜索标题。所以我在 yocto tmp 文件夹中添加了路径,该文件夹包含构建 rootfs 所需的所有头文件。添加后,它再次编译成功。但是当我添加 sndfile 库进行链接时,问题就开始了。这是链接命令和错误:

arm-linux-gnueabihf-g++ -L"/home/stas/ZedboardPetalinuxFS/usr/lib" -L"/home/stas/ZedboardPetalinuxFS/lib" -o "test.elf"  ./src/main.o   -lpthread -lsndfile
/opt/Xilinx/SDK/2016.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/../lib/gcc/arm-linux-gnueabihf/5.2.1/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lsndfile

我查看 usr/lib 以检查是否存在 libsndfile.so,但我只找到了 libsndfile.so.1 和 ibsndfile.so.1.27。但 pthread 也是如此,链接器不会为此抱怨。我决定手动创建 libsndfile.so(我将它链接到 libsndfile.so.1)。Linker 不再抱怨它,而是开始抱怨它的依赖关系。因此,我还为所有依赖项及其依赖项创建了 .so 文件,并添加了它们以进行链接。然后就成功了。最后,链接命令如下所示:

arm-linux-gnueabihf-g++ -L"/home/stas/ZedboardPetalinuxFS/usr/lib" -L"/home/stas/ZedboardPetalinuxFS/lib" -o "test.elf"  ./src/main.o   -lpthread -lvorbisenc -lvorbis -logg -lFLAC -lsndfile

那么第一个问题来了——为什么我不需要 pthread 的 .so 文件,但所有其他库都需要它?或者更一般的——我什么时候需要 .so 文件,什么时候 .so.X 文件就足够了?

2. 简单的应用程序 - 另一种方法

第一次尝试后,我想我应该制作另一个图像,这次更适合开发。幸运的是,在 Yocto 中这很容易——我只需要修改一行:

EXTRA_IMAGE_FEATURES = "debug-tweaks eclipse-debug dev-pkgs"

dev-pkgs 选项为所有已安装的软件包添加 -dev 软件包。所以现在我有了包含所有需要的头文件的 rootfs,以及指向它们应该在哪里的 .so 文件。
在编译之前,我删除了不必要的Include路径,只留下rootfs中的一个,并删除了除pthread和sndfile之外的所有库。但后来我得到了新的错误:

arm-linux-gnueabihf-g++ -L"/home/stas/ZedboardPetalinuxFS/usr/lib" -L"/home/stas/ZedboardPetalinuxFS/lib" -o "test.elf"  ./src/main.o   -lsndfile -lpthread
/opt/Xilinx/SDK/2016.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/../lib/gcc/arm-linux-gnueabihf/5.2.1/../../../../arm-linux-gnueabihf/bin/ld: cannot find /lib/libpthread.so.0
makefile:48: polecenia dla obiektu 'test.elf' nie powiodły się (commands for ‘test.elf’ did not succeed)
/opt/Xilinx/SDK/2016.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/../lib/gcc/arm-linux-gnueabihf/5.2.1/../../../../arm-linux-gnueabihf/bin/ld: cannot find /usr/lib/libpthread_nonshared.a

我发现它在我的根文件夹中查找库。在谷歌(和 SO:))中快速搜索告诉我我应该设置 --sysroot 变量。所以我将它添加到 Eclipse 选项(在链接器选项中的杂项卡中),如下所示:

--sysroot=/home/stas/ZedboardPetalinuxFS

所以现在链接器命令看起来像这样:

arm-linux-gnueabihf-g++ -L"/home/stas/ZedboardPetalinuxFS/usr/lib" -L"/home/stas/ZedboardPetalinuxFS/lib" --sysroot=/home/stas/ZedboardPetalinuxFS -o "test.elf"  ./src/main.o   -lsndfile -lpthread

并且都成功了!我还编写了使用 pthreads 和 sndfile 的简单示例,它也有效。但为什么?这让我想到第二个问题:在这种情况下,为什么我需要 --sysroot 选项?我一般什么时候需要使用这个选项?为什么这次我不必将所有依赖项添加到链接命令中?

3. 另一个想法

在这一点上,我有一个想法,检查会发生什么,如果我添加--sysroot选项,让 rootfs 填充旧的非开发图像。但这给了我新的错误:

arm-linux-gnueabihf-g++ -L"/home/stas/ZedboardPetalinuxFS/usr/lib" -L"/home/stas/ZedboardPetalinuxFS/lib" --sysroot=/home/stas/ZedboardPetalinuxFS -o "test.elf"  ./src/main.o   -lpthread -lvorbisenc -lvorbis -logg -lFLAC -lsndfile
/opt/Xilinx/SDK/2016.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/../lib/gcc/arm-linux-gnueabihf/5.2.1/../../../../arm-linux-gnueabihf/bin/ld: cannot find crt1.o: No such file or directory
makefile:48: polecenia dla obiektu 'test.elf' nie powiodły się
/opt/Xilinx/SDK/2016.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/../lib/gcc/arm-linux-gnueabihf/5.2.1/../../../../arm-linux-gnueabihf/bin/ld: cannot find crti.o: No such file or directory
/opt/Xilinx/SDK/2016.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/../lib/gcc/arm-linux-gnueabihf/5.2.1/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lpthread
/opt/Xilinx/SDK/2016.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/../lib/gcc/arm-linux-gnueabihf/5.2.1/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lm

那么第三个问题——这个错误是什么意思?

首先十分感谢!

有害的

为什么我不需要 pthread 的 .so 文件,但所有其他库都需要它?

交叉编译器通常带有 C 运行时(包括 pthread),通常位于交叉编译器安装的一部分的目录中。

链接器内置了库的搜索路径。这些是关于 sysroot 的,默认情况下将设置为搜索交叉编译器自己包含的目标 C 运行时。如果您添加了任何-L选项,它会首先搜索这些选项,然后移至这些预定义的目录。

当您链接pthread它时,至少会libpthread.a在交叉编译器的库目录中找到它

或者更一般的——我什么时候需要 .so 文件,什么时候 .so.X 文件就足够了?

Linux 中的共享库通常具有主要和次要版本号。库在具有相同主要版本的不同次要版本之间是 ABI 兼容的,但在主要版本之间不兼容。有时有三个级别的版本,但原理是相似的。

安装库时,通常使用全名安装实际文件,例如。libmy.so.1.2,然后提供指向libmy.so.1和 的符号链接libmy.so

如果您链接的应用程序可以与任何库版本一起使用,那么您只需指定名称,例如。-lmy. 在这种情况下,您需要从libmy.so到的符号链接libmy.so.1

如果您需要特定版本,则将-l:libmy.so.1. ':' 表示文字文件名。

链接器脚本可能会影响事情,并可能导致选择特定版本,即使您确实指定了短名称。

为什么在这种情况下需要 --sysroot 选项?我一般什么时候需要使用这个选项?

什么--sysroot是将给定的路径添加到通常用于搜索包含和库的所有搜索目录中。在交叉编译时(就像您现在所做的那样)最有用的是让编译器和链接器在目标根目录中搜索,而不是在构建主机自己的根目录中搜索。

如果您指定了一个 sysroot,您可能不需要指定包含路径 via-I或链接器路径 via -L,假设文件位于目标根目录中的正常位置。

为什么这次我不必将所有依赖项添加到链接命令中?

一种可能的情况是,第一次,sndfile进行静态而不是动态链接。如果您的第一个根映像仅sndfile.a在 lib 目录中或搜索路径上的其他位置,则会发生这种情况为了满足sndfile.a的要求,还需要链接其他库。

当链接sndfile.so依赖项时,将通过动态链接过程自动加载。

这只是目前的一个工作理论。

那么第三个问题——这个错误是什么意思?

这意味着它甚至找不到要链接的 C 运行时库。

如第一个问题所述,它之前在预定义的搜索路径(相对于预定义的 sysroot)中查找 C 运行时,该路径位于交叉编译器提供的 C 运行时。

您通过提供自己的 sysroot 扰乱了这一点。它现在只搜索目标根。由于此目标根文件系统没有安装开发库,因此找不到 C 运行时。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章