与CMake交叉编译:链接器错误

时间:2020-07-21 22:25:34

标签: c++ cmake linker cross-compiling linker-errors

我正在尝试在ubuntu机器上交叉编译树莓派(32位armv8)的项目。我使用crosstool-NG建立了工具链并进行了编译,但是链接失败。我的CMake工具链文件如下:

SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_SYSTEM_VERSION 1)

set(CMAKE_SYSROOT /home/stone/development/raspberry_pi/armv8-rpi3-linux-gnueabihf/armv8-rpi3-linux-gnueabihf/sysroot)

SET(CMAKE_C_COMPILER /home/stone/development/raspberry_pi/armv8-rpi3-linux-gnueabihf/bin/armv8-rpi3-linux-gnueabihf-gcc)
SET(CMAKE_CXX_COMPILER /home/stone/development/raspberry_pi/armv8-rpi3-linux-gnueabihf/bin/armv8-rpi3-linux-gnueabihf-g++)

SET(CMAKE_FIND_ROOT_PATH /home/stone/development/raspberry_pi/armv8-rpi3-linux-gnueabihf)

SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

我有一些链接器找不到的库。问题出在我的sysroot上。我从pi复制了/usr/lib到由crosstool-NG创建的sysroot文件夹。链接的库位于sysroot/usr/lib/arm-linux-gnueabihf中。

但是,链接器没有检查该目录,而是检查sysroot / usr / lib和其他一些目录,但是由于某种原因,它不检查arm-linux-gnueabihf目录。

在pi上,我可以运行ld -lasound --verbose并获得以下输出:

attempt to open //usr/local/lib/arm-linux-gnueabihf/libasound.so failed
attempt to open //usr/local/lib/arm-linux-gnueabihf/libasound.a failed
attempt to open //lib/arm-linux-gnueabihf/libasound.so failed
attempt to open //lib/arm-linux-gnueabihf/libasound.a failed
attempt to open //usr/lib/arm-linux-gnueabihf/libasound.so succeeded

因此可以在pi上正确找到它。

当我使用crosstool-NG生成的ld执行相同操作时:

attempt to open /home/stone/development/raspberry_pi/armv8-rpi3-linux-gnueabihf/armv8-rpi3-linux-gnueabihf/bin/../sysroot/home/stone/x-tools/armv8-rpi3-linux-gnueabihf/armv8-rpi3-linux-gnueabihf/lib/libasound.so failed
attempt to open /home/stone/development/raspberry_pi/armv8-rpi3-linux-gnueabihf/armv8-rpi3-linux-gnueabihf/bin/../sysroot/home/stone/x-tools/armv8-rpi3-linux-gnueabihf/armv8-rpi3-linux-gnueabihf/lib/libasound.a failed
attempt to open /home/stone/development/raspberry_pi/armv8-rpi3-linux-gnueabihf/armv8-rpi3-linux-gnueabihf/bin/../sysroot/usr/local/lib/libasound.so failed
attempt to open /home/stone/development/raspberry_pi/armv8-rpi3-linux-gnueabihf/armv8-rpi3-linux-gnueabihf/bin/../sysroot/usr/local/lib/libasound.a failed
attempt to open /home/stone/development/raspberry_pi/armv8-rpi3-linux-gnueabihf/armv8-rpi3-linux-gnueabihf/bin/../sysroot/lib/libasound.so failed
attempt to open /home/stone/development/raspberry_pi/armv8-rpi3-linux-gnueabihf/armv8-rpi3-linux-gnueabihf/bin/../sysroot/lib/libasound.a failed
attempt to open /home/stone/development/raspberry_pi/armv8-rpi3-linux-gnueabihf/armv8-rpi3-linux-gnueabihf/bin/../sysroot/usr/lib/libasound.so failed

找不到它,因为它不在arm-linux-gnueabihf目录中。我将库.so文件从sysroot / usr / lib / arm-linux-gnueabihf复制到sysroot / usr / lib,它可以成功编译和链接,但是我想这样做,因此不必这样做。如何使链接程序检查arm-linux-gnueabihf目录?

编辑:我还从pi复制了/etc/ld.so.conf和/etc/ld.so.conf.d到我的sysroot中,但是它似乎并不影响链接器。

编辑:经过进一步研究,看来这可能是由于gcc-multiarch引起的。我不确定那是什么,但希望我能弄清楚

编辑:我验证了链接器的确没有在搜索arm-linux-gnueabihf路径:

 ./armv8-rpi3-linux-gnueabihf-ld --verbose | grep -i "search"

输出:

SEARCH_DIR("=/home/stone/x-tools/armv8-rpi3-linux-gnueabihf/armv8-rpi3-linux-gnueabihf/lib"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");

2 个答案:

答案 0 :(得分:1)

好吧,我知道了。 here是我从中了解到使它起作用的技巧的仓库。我对此回购表示感谢,没有它,我将无法正常工作。

问题出在链接器上。由crosstool-ng插入的普通旧binutils附带的链接器不会搜索arm-linux-gnueabihf子目录。这些目录是由于Debian多体系结构而存在的,为了获得在该目录中看起来的链接器,需要对binutils进行修补。以下说明假定您已经基于rpi3示例生成了ct-ng配置。

在树莓派上,我安装了binutils-source软件包:

$ sudo apt install binutils-source

这将允许访问/ usr / src / binutils / patches中的补丁文件。

在主机上,您需要在构建工具链的目录(ct-ng配置文件所在的目录)中添加一个patchs目录。它必须具有反映crosstool-ng存储库中packages的结构的特定结构(即,在patch /中,您必须具有包含软件包名称的目录,在其中必须具有版本号,并且在其中是放置补丁的位置。):

$ cd your_toolchain_directory
$ mkdir -p patches/binutils/2.31.1/

现在我们可以将补丁文件从pi复制到主机。我们需要的特定补丁是129_multiarch_libpath.patch:

$ cd patches/binutils/2.31.1/
$ scp pi@raspberrypi:/usr/src/binutils/129_multiarch_libpath.patch

现在我们有了补丁,我们需要更新配置文件以告知ct-ng包括本地补丁,并为gcc启用multiarch标志。您可以使用ct-ng menuconfig来执行此操作,因此请使用配置文件返回目录并运行:

$ ct-ng menuconfig

在路径和其他选项中,您需要将修补程序源更改为捆绑的,然后更改为本地,然后将$ {CT_TOP_DIR} / patches添加为本地修补程序目录。这应该在.config文件的解压缩部分下产生以下几行:

CT_PATCH_BUNDLED_LOCAL=y
CT_PATCH_ORDER="bundled,local"
CT_PATCH_USE_LOCAL=y
CT_LOCAL_PATCH_DIR="${CT_TOP_DIR}/patches"

接下来,您需要在gcc选项中添加--enable-multiarch标志。再次使用menuconfig,转到C编译器设置。将--enable-multiarch添加到gcc Extra配置设置中。配置文件在gcc设置中应具有以下内容:

CT_CC_GCC_EXTRA_CONFIG_ARRAY="--enable-multiarch"

保存配置。我们需要做的最后一件事是导出变量。

$ export DEB_TARGET_MULTIARCH=arm-linux-gnueabihf

现在我们可以构建工具链:

$ ct-ng build

完成后,您可以进入生成的工具链的bin目录并运行:

$ ./ld --verbose | grep -i "search"

,您应该看到arm-linux-gnueabihf目录现在位于搜索路径中。真是个过程。

答案 1 :(得分:-1)

您需要改用静态库。然后可执行文件将包含库的二进制文件。 但是请记住,可执行文件会更大(显然取决于哪个lib ...)。 使用交叉编译时,应检查所使用的库在执行程序的其他环境中是否存在。 解决方法是根据CmakeList.txt文件添加STATIC字