原因:官网提供的预编译包使用的glibc版本为2.28,而16年编译的Pine A64系统上使用的还是glibc2.23。由于缺乏高版本的符号支持,使用新版本的编译器编译的程序可能会出现找不到符号一类的问题。(在重新编译系统和编译器之间,我选择了后者,因为实在不知道该如何配置多环境glibc了。。)

参考:https://preshing.com/20141119/how-to-build-a-gcc-cross-compiler/ 基本上就是翻译了

>>> 本文中的所有操作都假设在用户的家目录下的gnu-aarch64文件夹~/gnu-aarch64/下执行 <<<
>>> 用于编译的文件夹以build-作为前缀,如build-gcc <<<
>>> 编译完成后的工具链安装在dist目录下 <<<
系统为Ubuntu 16.04 Server
这里使用/home/esper/作为用户的家目录。

一套完整的编译工具链由三个部分组成,binutilsgccglibc
三者的功能分别如下:
binutils:顾名思义,与二进制binary相关,负责对二进制文件相关的操作,比如常见的ld(可能全称是link dynamics),即链接动态库,此时的文件已经是编译为二进制的对象文件object file了;在之前的曾经提到过的strip,删除二进制文件中不必要的符号信息,等等。
gcc:全称GNU Compiler Collection,是GNU开源计划的编译器套件。完成的功能是将高级语言转化为对应的机器代码/二进制文件。stdc++库是和gcc一同发布的 -> 想要降级libstdc++,就要降级gcc。
glibcglibc是GNU发布的libc库,即c运行库。glibc是linux系统中最底层的应用程序编程接口Application Programming Interface, API,几乎其它任何运行库都会依赖于glibc。(摘自百度百科)

事先说明:

  1. 如果编译过程中出现了错误,不要慌!在排查完自己步骤上的错误之后,别忘记怀疑软件和系统!!(惨痛的教训)
  2. 如果遇到了error: cannot compute suffix of object files问题的话,说明你可能是提前开始了gcc的编译,或者没有配置好必要的环境变量。

第一步 准备必要环境

这一步包括所有相关的软件及其相关配置等。

必要软件包

通过包管理器安装-辅助软件包:texinfo, gettext, bison, 用于编译的gcc, make
源码-主要软件包:目标版本的gcc, binutils, glibc, 目标系统对应版本的linux内核源码
源码-辅助软件包:gmp, isl, mpc, mpfr, libiconv
其中软件的版本可通过包内的INSTALL文件中对软件包的要求进行确定。
其中不同发行网站(比如gnu官方和arm官方)提供的gcc源码包内,有的直接提供了可用版本的辅助软件包,有的可以通过contrib目录下的download_prerequisites脚本进行下载。

必要环境变量

需要确保编译完的输出文件夹的bin目录在搜索路径search path中。

export PATH=/home/esper/gnu-aarch64/dist/bin:$PATH

因为交叉工具链的编译是一个可以称为自举的过程,即先编译一部分,然后这一部分参与编译另一部分,直至编译完成。从文首的引用中借图可以清晰展示如下:

1

gccglibc都是交叉工具链的一部分,作为一个整体的工具链,像一个人走路一样左脚、右脚地迈进,而不是各自独立完成编译然后组合在一起。因而,在过程步骤上有点复杂。

第二步 编译安装binutils

为了编译安装软件,对于二进制文件的操作是必不可少的。因而,要先编译用于目标平台的binutils以使得接下来可以修改能在目标平台上运行的程序。

tar xf binutils-2.26.1.tar.gz
mkdir build-binutils
cd build-binutils
../binutils-2.26.1/configure --prefix=/home/esper/gnu-aarch64/dist --target=aarch64-linux-gnu --disable-multilib
make -j4
make install
cd ..

由于configure命令不允许使用相对路径,故需要使用绝对路径。将其替换为自己的用户名。
完成后,直接在命令行输入aarch64,然后多按几次tab键,应该会出现诸如aarch64-linux-gnu-ld的命令补全提示。
如果现象与上述一致,则该步骤成功完成。

第三步 准备linux内核头文件

参考我的这篇博客以获得pine64对应的内核源码。
但是由于在这里,我们的内核头文件不是为系统配置使用的,因而无需使用文中提到的来自longsleep大神的安装脚本。

tar xf linux-pine64-3.10.104-2-pine64.tar.gz
cd linux-pine64-3.10.104-2-pine64
make ARCH=arm64 INSTALL_HDR_PATH=/home/esper/gnu-aarch64/dist/aarch64-linux-gnu headers_install
cd ..

将头文件安装到以架构命名的子文件夹中。这样做的好处是允许系统中同时配置有多个不同环境的编译套件,而且似乎gcc也贯彻落实了这一点——如果不这么做的话,往往会出现意料之外的错误。

第四步 编译安装gcc套件

gcc套件只是工具链的一部分,获得的gcc源码包中还含有libstdc++一类同捆发行的依赖库,在此时并不能完成编译。
可以将gmp, isl, mpc, mpfr, libiconv的源码文件夹链接或是直接解压到gcc源码目录下,configure命令若是识别到了不带版本后缀的文件夹名的话,会试图将该源码包编译,并用于后续的编译过程。否则需要在系统路径提供安装好的、满足版本要求的对应软件包。

tar xf gcc-arm-src-snapshot-8.3-2019.03.tar.xz
mkdir build-gcc
cd build-gcc
../gcc-arm-src-snapshot-8.3-2019.03/configure --target=aarch64-linux-gnu --prefix=/home/esper/gnu-aarch64/dist --with-bugurl=https://bugs.linaro.org/ --enable-gnu-indirect-function --enable-shared --disable-libssp --disable-libmudflap --enable-checking=release --enable-languages=c,c++,fortran --enable-fix-cortex-a53-843419 --disable-multilib
make -j4 all-gcc
make install-gcc
cd ..

如果需要提供ada支持的话,需要安装flex包。由于我的后续工作中用不到,且为了节约时间,就没有编译部分语言的支持。 如果对于configure的参数有疑问的话,可以通过gcc -v获得对应gcc编译器的编译配置参数以参考。

第五步 构建glibc初始环境

根据参考文章的作者描述,除开configure之外,该步骤属于临时性但又不得不做的措施。

tar xf glibc-2.23.tar.xz
mkdir build-glibc
cd build-glibc
../glibc-2.23/configure --prefix=/home/esper/gnu-aarch64/dist/aarch64-linux-gnu --build=x86_64-linux-gnu --host=aarch64-linux-gnu --target=aarch64-linux-gnu --with-headers=/home/esper/gnu-aarch64/dist/aarch64-linux-gnu/include --disable-multilib --disable-werror
make install-bootstrap-headers=yes install-headers
make -j4 csu/subdir_lib
install csu/crt1.o csu/crti.o csu/crtn.o /home/esper/gnu-aarch64/dist/aarch64-linux-gnu/lib
aarch64-linux-gnu-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o /home/esper/gnu-aarch64/dist/aarch64-linux-gnu/lib/libc.so
touch /home/esper/gnu-aarch64/dist/aarch64-linux-gnu/include/gnu/stubs.h
cd ..

其中根据参考文章的作者描述,glibc的configure必须显式指明build, host, target三个平台参数值。
这里的configure添加了--disable-werror参数,目的在于取消编译器将警告作为错误处理,进而终止编译过程的行为。该参数在软件的编写过程中十分有效,但是在编译一个已经公开发行且没有出现大问题的软件的时候,emm...还是关掉它吧

第六步 编译gcc支持库

cd build-gcc
make -j4 all-target-libgcc
make install-target-libgcc
cd ..

第七步 编译glibc

此时才能使用目标平台的gcc编译glibc。

cd build-glibc
make -j4
make install
cd ..

第八步 完成gcc编译

cd build-gcc
make -j4
make install
cd ..

然后dist目录下就是一套完整的交叉编译工具链了。经过测试,该工具链已经可以生成能在目标平台运行的程序了,但在移动位置之后使用我还没试过。理论上是没问题的,因为arm官方发布的预编译包似乎就是这样。祝好运!

===========================================================
当场补充

相信看到这里,并且在机器上一步一步跟着做的读者(如果有的话)应该是长舒了一口气。然而,在下要在这里提一句,ubuntu上有预编译好的交叉编译工具链,如果你不知道的话。

sudo apt install gcc-5-aarch64-linux-gnu g++-5-aarch64-linux-gnu

(逃

标签: none

添加新评论