如何在交叉编译时使用外部库?

38

我正在为树莓派ARM目标在x86 Ubuntu机器上编写代码。我使用的是gcc-linaro-armhf工具链。我能够交叉编译并在pi上运行一些独立程序。现在,我想将我的代码与外部库(如ncurses)链接起来。我该如何实现?

我应该只是将我的程序与主机上现有的ncurses库链接,然后在ARM上运行吗?(我认为这不会奏效) 我需要获取ARM架构的源码或预编译版本,将其放入我的库路径中,然后进行编译吗?

在这种情况下,最佳实践是什么?

我还想知道C标准库是如何工作的。在我的程序中,我使用了stdio函数,在交叉编译后它可以正常工作,而我没有进行任何特殊操作。我只是在makefile中提供了我的arm gcc路径。那么,它是如何获取正确的std头文件和库的呢?

5个回答

31

关于您的一般问题:

C库是你的交叉工具链的一部分。这就是为什么头文件可以被找到,程序能正确链接和运行的原因。对于一些其他非常基本的系统库,比如libm和libstdc++(不是每种情况都适用,这取决于工具链的配置),也是如此。

通常在处理交叉开发时,您需要某种方式来获取所需库的交叉编译版本。在这种情况下使用二进制文件是非常罕见的。特别是使用ARM硬件时,因为有很多不同的配置,并且通常每个设备都会以不同方式进行精简。这就是为什么二进制文件在不同设备和Linux配置之间不太具有二进制兼容性。

如果您在树莓派上运行Ubuntu,则有机会在互联网上或甚至在一些Ubuntu apt存储库中找到合适的ncurses库。然而,典型的方法是使用您拥有的特定工具链交叉编译库。

在需要交叉编译许多复杂库的情况下,有一些解决方案可以使生活变得更加轻松,例如buildroot或ptxdist。这些程序可以为嵌入式设备构建完整的Linux内核和根文件系统。

然而,在您的情况下,只要您想要ncurses,您就可以自己编译源代码。您只需要下载源代码,使用--host选项指定您的工具链运行configure--prefix选项将选择安装目录。在运行makemake install后,如果一切顺利,您将获得一组头文件和用于应用程序链接的ARM编译库。

关于交叉编译,您肯定会在互联网上找到大量信息,也许ncurses在其随附文档中有一些指针。


谢谢,这很有帮助。还有一个一般性的问题。 关于C库,我在makefile中没有指定任何路径。我只提供了arm-gcc的路径,那么它如何知道在哪里找到stdlib呢?我知道对于外部库,我可以使用-L来指定路径。 - Punit Soni
@PunitSoni arm-gcc会根据相对路径自行计算,因此您不能更改交叉编译器的目录结构。 - cifer
3
可能举个例子来说明这些选项(--host--prefix)是如何工作的会有所帮助。 - Michael

17

针对查询 交叉工具中C库的工作原理

在配置期间编译和构建交叉工具链时,它们将提供 sysroot。

例如:--with-sysroot=${CLFS_CROSS_TOOLS}

--with-sysroot --with-sysroot=dir

告诉 GCC 将 dir 视为包含目标操作系统根文件系统(子集)的树的根。目标系统头文件、库和运行时对象文件将在其中搜索。更具体地说,这就像将 --sysroot=dir 添加到构建的编译器的默认选项中一样。与此选项废弃的 --with-headers 和 --with-libs 选项不同,指定的目录不会复制到安装树中。如果未指定 --with-sysroot 参数,则默认值为 ${gcc_tooldir}/sys-root。如果指定的目录是 ${exec_prefix} 的子目录,则如果移动安装树,则会相对于 GCC 二进制文件找到它。

因此,它在编译时不会查找 /lib /usr/include,而是在 /Toolchain/(libc) 和 (include 文件) 中查找

可以通过以下方式进行检查

arm-linux-gnueabihf-gcc -print-sysroot

这将显示 libc 的位置。

另外

arm-linux-gnueabihf-gcc -print-search-dirs

可以给你一个清晰的画面。


那么,如果我有一个嵌入式系统的ISO文件,我可以挂载该ISO文件(只读),并使用--with-sysroot使交叉编译器在构建新软件包时使用所有这些系统库吗? - pavon

2

显然,您需要为目标ARM编译ncurses - 主机上的这个库对您没有任何好处[除非您的主机有ARM处理器 - 但您说是x86,显然不是这种情况]。

可能会有一些预构建库可用,但我怀疑找到一个符合您特定条件且可用的库比从源代码构建库更费力 - 这应该不难,而且我预计ncurses 不需要太多时间来构建。


谢谢,我只是想确认这是最好的方法。那么,在这种情况下,stdlib如何工作?我没有在这里为ARM编译或链接stdlib。 - Punit Soni

1
如果您打算在交叉编译工具链中使用ncurses库,则需要准备其arm-built二进制文件。
至于您的第二个问题,它是如何与std libs一起工作的,实际上编译/链接程序所使用的并不是系统libc/libm。也许您可以从编译器的--print-file-name=选项中看到它:
arm-none-linux-gnuabi-gcc --print-file-name=libm.a

...(my working folder)/arm-2011.03(arm-toolchain folder)/bin/../arm-none-linux-gnuabi/libc/usr/lib/libm.a

arm-none-linux-gnuabi-gcc --print-file-name=libpthread.so

...(my working folder)/arm-2011.03(arm-toolchain folder)/bin/../arm-none-linux-gnuabi/libc/usr/lib/libpthread.so

我认为你的树莓派工具链可能是一样的。你可以试一下这个。

1

Vinay的回答非常可靠。只有一个更正,在为树莓派编译ncurses库时,设置rootfs的选项是--sysroot=<dir>而不是--with-sysroot。这是我在使用以下编译器时发现的:

arm-linux-gnueabihf-gcc --version
arm-linux-gnueabihf-gcc(crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03)4.8.3 20140303(预发布版)
Copyright(C)2013 Free Software Foundation, Inc.
这是自由软件;请参阅源代码以获取复制条件。没有保证;甚至没有适合特定用途的保证。

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