从源码编译 LoongArch GNU 工具链
1. 制作以 LoongArch 为目标的交叉工具链
1.1. 获取源码包
- 下载页面:龙芯开源社区网站 - LoongArch GCC 8.3 交叉工具链 - 源码下载
- 源码包名称如:
loongarch-gcc8-linux-gnu-rc1.0-src-2022-04-22.tar
1.2. 展开源码包并校验完整性
展开源码包:
$ tar xvf loongarch-gcc8-linux-gnu-rc1.0-src-2022-04-22.tar
目录结构:
$ cd loongarch-gcc8-linux-gnu-rc1.0-src-2022-04-22
$ tree .
.
├── binutils-2.31-dc545ca87e.tar.xz
├── gcc-8.3.0-b4748c190d.tar.xz
├── glibc-2.28-310d27ffef.tar.xz
├── sha1sum
└── versions
0 directories, 5 files
使用 sha1sum
命令校验各文件完整性:
$ sha1sum -c < sha1sum
binutils-2.31-dc545ca87e.tar.xz: OK
gcc-8.3.0-b4748c190d.tar.xz: OK
glibc-2.28-310d27ffef.tar.xz: OK
versions: OK
各项目源码包列表:
- binutils (基础版本 2.31)
- gcc (基础版本 8.3.0)
- glibc (基础版本 2.28)
1.3. 进行其他准备工作
以下步骤中,工具链安装根路径均表示为 <installation_prefix>
。
下载 GMP, MPFR, MPC, ISL 库源码
编译 GCC 依赖于以上四种库。用户在编译 GCC 之前,将它们的源码路径链接到 GCC 源码目录中即可识别。
这些库最终均静态链接到 GCC 二进制中。
用户可直接使用 GCC 源码中提供的 download_prerequisites
脚本,从上游网站下载它们的源码:
$ cd <gcc_srcdir>
$ contrib/download_prerequisites
gmp-6.1.0.tar.bz2: OK
mpfr-3.1.4.tar.bz2: OK
mpc-1.0.3.tar.gz: OK
isl-0.18.tar.bz2: OK
All prerequisites downloaded successfully.
$ ls -d gmp mpfr mpc isl
gmp isl mpc mpfr
这些上游库源码中包含 GNU 架构名称处理脚本,
即 config.guess
和 config.sub
,目前需要手动更新为支持 LoongArch 的版本。
$ find gmp/ mpfr/ mpc/ isl/ -name config.guess -type f -exec sh -c 'chmod +w {}; cp -v config.guess {}' \;
'config.guess' -> 'gmp/config.guess'
'config.guess' -> 'mpfr/config.guess'
'config.guess' -> 'mpc/config.guess'
'config.guess' -> 'isl/config.guess'
$ find gmp/ mpfr/ mpc/ isl/ -name config.sub -type f -exec sh -c 'chmod +w {}; cp -v config.sub {}' \;
'config.sub' -> 'gmp/config.sub'
'config.sub' -> 'mpfr/config.sub'
'config.sub' -> 'mpc/config.sub'
'config.sub' -> 'isl/config.sub'
安装 Linux 内核头文件
编译 Glibc 库依赖于 Linux 内核头文件,目前可从 Loongnix deb 仓库 获得,包名为 linux-libc-dev
,当前版本为 4.19.190-rc6.lnd.9。
运行以下命令即可在安装路径 <installation_prefix>
下安装 Linux 内核头文件,供 Glibc 编译使用。
$ PKGNAME=linux-libc-dev_4.19.190-rc6.lnd.9_loongarch64.deb
$ wget http://pkg.loongnix.cn/loongnix/pool/main/l/linux/${PKGNAME}
$ ar x ${PKGNAME} data.tar.xz
$ mkdir -p <installation_prefix>/sysroot
$ tar -xvf data.tar.xz -C <installation_prefix>/sysroot
$ mv <installation_prefix>/sysroot/usr/include/{loongarch64-linux-gnu/,}asm
$ rmdir <installation_prefix>/sysroot/usr/include/loongarch64-linux-gnu
1.4. 交叉编译
编译 binutils
假设 binutils 源码目录为 <binutils_srcdir>
,在空白构建目录下执行命令:
$ <binutils_srcdir>/configure --prefix=/ --target=loongarch64-linux-gnu --disable-werror
$ make -j `nproc` && make DESTDIR=<installation_prefix> install
此时 <installation_prefix>
目录的结构如下:
.
├── bin
├── loongarch64-linux-gnu
│ ├── bin
│ └── lib
├── share
│ ├── info
│ ├── locale
│ └── man
└── sysroot
├── lib
└── usr
编译 GCC 第一遍 (pass 1)
编译第一遍 GCC 的目的仅在于编译 Glibc 库。
假设 GCC 源码目录为 <gcc_srcdir>
,在空白构建目录下执行命令:
$ export PATH=<installation_prefix>/bin:$PATH
$ <gcc_srcdir>/configure --prefix=<installation_prefix> --target=loongarch64-linux-gnu --with-sysroot=<installation_prefix>/sysroot --disable-nls --disable-shared --without-headers --with-newlib --disable-libatomic --disable-threads --enable-languages=c
$ make all-gcc all-target-libgcc -j `nproc`
$ make install-gcc install-target-libgcc
此时 <installation_prefix>
目录的结构如下:
.
├── bin
├── include
├── lib
│ └── gcc
├── libexec
│ └── gcc
├── loongarch64-linux-gnu
│ ├── bin
│ └── lib
├── share
│ ├── info
│ ├── locale
│ └── man
└── sysroot
├── lib
└── usr
编译 Glibc 库
假设 Glibc 源码目录为 <glibc_srcdir>
,在空白构建目录下执行命令:
$ export PATH=<installation_prefix>/bin:$PATH
$ <glibc_srcdir>/configure --prefix=/usr --host=loongarch64-linux-gnu --with-headers=<installation_prefix>/sysroot/usr/include
$ mkdir <installation_prefix>/sysroot/usr/lib64 && ln -sf usr/lib64 <installation_prefix>/sysroot/lib64
$ mkdir <installation_prefix>/sysroot/usr/lib && ln -sf usr/lib <installation_prefix>/sysroot/lib
$ make -j `nproc`
$ make install_root=<installation_prefix>/sysroot MAKEINFO=: install
此时 <installation_prefix>/sysroot
目录的结构如下:
sysroot
├── etc
├── lib -> usr/lib
├── lib64 -> usr/lib64
├── sbin
├── usr
│ ├── bin
│ ├── include
│ ├── lib
│ ├── lib64
│ ├── libexec
│ ├── sbin
│ └── share
└── var
└── db
需要注意的是,此处的 lib | sysroot/lib
路径不可省略。
原因是 LoongArch GCC 支持多库 (multilib) 机制,允许根据编译选项采用不同的库搜索路径,
以适应多种不同的传参返回规范,而每个多库搜索路径都包括一个固定的参考路径(即 lib
)和后续叠加的相对路径
(由 GCC 编译选项动态确定)。多库搜索路径可正确访问的必要条件是固定参考路径存在。
对于在操作系统发行版上的本地编译器,该路径由发行版负责创建。
编译 GCC 第二遍 (pass 2)
假设 GCC 源码目录为 <gcc_srcdir>
,在空白构建目录下执行命令:
# --target --with-sysroot --with-build-sysroot 选项需要保留,其余功能选择部分可自行定义
$ <gcc_srcdir>/configure --target=loongarch64-linux-gnu --prefix=<installation_prefix> --with-sysroot=<installation_prefix>/sysroot --with-build-sysroot=<installation_prefix>/sysroot --enable-languages=c,c++,fortran --enable-checking=release
$ make -j `nproc`
$ make install
此时
.
├── bin
├── include
├── lib
│ └── gcc
├── lib64
├── libexec
│ └── gcc
├── loongarch64-linux-gnu
│ ├── bin
│ ├── include
│ ├── lib
│ └── lib64
├── share
│ ├── gcc-8.3.0
│ ├── info
│ ├── locale
│ └── man
└── sysroot
├── etc
├── lib -> usr/lib
├── lib64 -> usr/lib64
├── sbin
├── usr
└── var
安装完毕执行以下命令:
$ loongarch64-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=......
COLLECT_LTO_WRAPPER=......
Target: loongarch64-linux-gnu
Configured with: ../gcc-8.3.0/configure --target=loongarch64-linux-gnu ......
Thread model: posix
gcc version 8.3.0 (GCC)
说明 GNU 交叉编译工具链安装成功。
2. 制作 LoongArch 本地工具链
- 本地编译器 build,host,target 架构均一致,运行 GCC configure 脚本时可省略相关选项。
- 用户可选择让工具链直接使用系统 glibc 库链接应用程序,或使用自行编译的 glibc 库。
2.1. 使用系统 glibc 库链接应用程序
依次编译 binutils 和 gcc 即可:
# Binutils
$ cd <binutils_builddir>
$ <binutils_srcdir>/configure --prefix=/ --disable-werror
$ make -j `nproc`
$ make install DESTDIR=<installation_prefix>
# GCC
$ cd <gcc_builddir>
$ <gcc_srcdir>/configure --prefix=/ --enable-languages=c,c++,fortran,lto --enable-checking=release --disable-bootstrap
$ make -j `nproc`
$ make install DESTDIR=<installation_prefix>
2.2. 自行编译 glibc 库
步骤与交叉编译相同,但运行 GCC configure 脚本时可省略 --target
选项。