使用 CMake 进行交叉编译:链接器错误
Cross compiling with CMake: linker errors
我正在尝试在我的 ubuntu 机器上为我的 raspberry pi(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 上。我将 /usr
和 /lib
从 pi 复制到由 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");
您需要改用静态库。然后可执行文件将包含库的二进制文件。
但请记住,可执行文件会更大(显然取决于哪个库...)。
当你使用交叉编译时,你应该检查你使用的库是否存在于你执行程序的其他环境中。
解决方案是根据 CmakeList.txt 文件
添加 STATIC 字
好的,我明白了。可以在 here 中找到我学习使它起作用的技巧的回购协议。我很感谢这个 repo,没有它我不会让它工作。
问题出在链接器上。由 crosstool-ng 引入的普通旧 binutils 附带的链接器不会搜索 arm-linux-gnueabihf 子目录。这些目录的存在是因为 Debian 多体系结构,为了获得在这样的目录中查找的链接器,binutils 需要打补丁。以下说明假定您已经基于 rpi3 示例生成了 ct-ng 配置。
在 raspberry pi 上,我安装了 binutils-source 包:
$ sudo apt install binutils-source
这将允许访问位于 /usr/src/binutils/patches 的补丁文件。
在主机上,您需要在构建工具链的目录(ct-ng 配置文件所在的目录)中添加一个 patches 目录。它必须有一个特定的结构来反映 crosstool-ng repo 中 packages 的结构(即在 patches/ 里面你必须有一个包含包名的目录,在里面你必须有版本号,在里面是你放置补丁的地方。):
$ 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 启用多架构标志。您可以使用 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 额外配置设置。配置文件应在 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 目录现在位于搜索路径中。好一个过程。
我正在尝试在我的 ubuntu 机器上为我的 raspberry pi(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 上。我将 /usr
和 /lib
从 pi 复制到由 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");
您需要改用静态库。然后可执行文件将包含库的二进制文件。 但请记住,可执行文件会更大(显然取决于哪个库...)。 当你使用交叉编译时,你应该检查你使用的库是否存在于你执行程序的其他环境中。 解决方案是根据 CmakeList.txt 文件
添加 STATIC 字好的,我明白了。可以在 here 中找到我学习使它起作用的技巧的回购协议。我很感谢这个 repo,没有它我不会让它工作。
问题出在链接器上。由 crosstool-ng 引入的普通旧 binutils 附带的链接器不会搜索 arm-linux-gnueabihf 子目录。这些目录的存在是因为 Debian 多体系结构,为了获得在这样的目录中查找的链接器,binutils 需要打补丁。以下说明假定您已经基于 rpi3 示例生成了 ct-ng 配置。
在 raspberry pi 上,我安装了 binutils-source 包:
$ sudo apt install binutils-source
这将允许访问位于 /usr/src/binutils/patches 的补丁文件。
在主机上,您需要在构建工具链的目录(ct-ng 配置文件所在的目录)中添加一个 patches 目录。它必须有一个特定的结构来反映 crosstool-ng repo 中 packages 的结构(即在 patches/ 里面你必须有一个包含包名的目录,在里面你必须有版本号,在里面是你放置补丁的地方。):
$ 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 启用多架构标志。您可以使用 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 额外配置设置。配置文件应在 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 目录现在位于搜索路径中。好一个过程。