如果你正在x86电脑上为龙芯3A5000开发软件,肯定会遇到一个头疼的问题:怎么把代码变成龙芯能跑的程序?这就是交叉编译工具链要干的事。我去年给龙芯3A5000移植一个开源项目时,整整折腾了两周才搞明白这里面的门道。
简单来说,交叉编译就像用中文说明书教老外做中国菜。你的x86电脑是那个会说中文的厨师,而龙芯3A5000就是等着吃菜的老外。GCC 12.1就是这个过程中最关键的"翻译官",它能把x86上的代码"翻译"成龙芯能懂的指令。
为什么非要GCC 12.1?三个硬核理由:
我在Ubuntu 22.04和Debian 11上都试过,实测Debian 11更稳。先来装这一堆依赖:
bash复制sudo apt update
sudo apt install -y texinfo autoconf automake libiberty-dev \
sed flex bison gzip gettext libelf-dev libgomp1 \
make tar libgmp-dev libmpfr-dev libmpc-dev \
libisl-dev build-essential
这里有个坑我踩过:texinfo看起来不重要,但少了它binutils根本编不过。曾经因为漏装这个,卡了我一整天。
官方源码包要从GNU FTP拉取,但国内访问经常抽风。我整理了个国内镜像的下载方案:
bash复制# binutils 2.38
wget https://mirrors.ustc.edu.cn/gnu/binutils/binutils-2.38.tar.xz
# GCC 12.1
wget https://mirrors.ustc.edu.cn/gnu/gcc/gcc-12.1.0/gcc-12.1.0.tar.xz
下完后一定要校验md5,我有次下到损坏的包,编译到一半报错,血泪教训:
bash复制echo "6e39cad1bb414add02b5b1169c18fdc5 binutils-2.38.tar.xz" | md5sum -c
echo "ed45b55ee859ada4b25a1e76e0c4d966 gcc-12.1.0.tar.xz" | md5sum -c
解压源码后,先更新config.guess和config.sub这两个文件。这是识别LoongArch架构的关键:
bash复制wget -O config.guess 'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess'
wget -O config.sub 'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub'
然后配置binutils时要用这个参数:
bash复制./configure --target=loongarch64-linux-gnu \
--prefix=/opt/loongarch64 \
--disable-multilib \
--with-arch=loongarch64 \
--with-abi=lp64d
注意**--with-abi=lp64d**这个参数,龙芯3A5000必须用这个ABI格式,我之前漏掉这个,编译出来的程序全都段错误。
在我折腾得焦头烂额时,偶然发现龙芯社区早就有人做好了现成的工具链。两个黄金资源:
孙海勇维护的CLFS项目:
bash复制git clone https://github.com/sunhaiyong1978/CLFS-for-LoongArch
官方build-tools仓库:
bash复制git clone https://github.com/loongson/build-tools
以CLFS为例,下载解压后直接能用:
bash复制tar xvf loongarch64-clfs-12.1-cross-tools-gcc-full.tar.xz -C /opt
编辑~/.bashrc时,这三个变量缺一不可:
bash复制export PATH=/opt/cross-tools/bin:$PATH
export LD_LIBRARY_PATH=/opt/cross-tools/lib:$LD_LIBRARY_PATH
export CROSS_COMPILE=loongarch64-linux-gnu-
测试是否配置成功:
bash复制loongarch64-unknown-linux-gnu-gcc -v
如果看到"gcc version 12.1.0"就说明搞定了。我建议用**-static**编译测试程序,避免动态链接库的问题:
bash复制loongarch64-unknown-linux-gnu-gcc -o hello hello.c -static
在我的Ryzen 5800X(8核16线程)机器上测试:
| 步骤 | 手动编译耗时 | 预编译方案耗时 |
|---|---|---|
| 环境准备 | 30分钟 | 5分钟 |
| 工具链构建 | 4-6小时 | 下载5分钟 |
| 问题排查 | 不确定 | 基本不需要 |
手动编译经常会遇到glibc版本问题,而预编译版本已经解决了这些依赖:
bash复制# 预编译工具链的libc版本
$ loongarch64-unknown-linux-gnu-gcc -print-file-name=libc.so
/opt/cross-tools/lib/libc.so
根据我的经验:
选手动编译如果:
选预编译版本如果:
这个错误折磨了我三天!现象是编译时报:
code复制Error: unrecognized option -#lp64d
解决方案是检查binutils的版本,必须用2.38以上,并且config.sub要更新到2022年后的版本。
初期我用动态链接编译程序,传到龙芯上就跑不起来。后来发现是因为目标机缺少对应的动态库。现在我的编译命令都加**-static**:
bash复制loongarch64-unknown-linux-gnu-gcc -o myapp myapp.c -static
如果遇到奇怪的系统调用错误,可能是内核头文件不匹配。预编译工具链已经包含正确的头文件,位置在:
code复制/opt/cross-tools/loongarch64-unknown-linux-gnu/include
不用每次都传到龙芯真机测试,可以安装qemu-user:
bash复制sudo apt install qemu-user-static
然后直接运行龙芯程序:
bash复制qemu-loongarch64-static ./myapp
设置工具链文件loongarch64.cmake:
cmake复制set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR loongarch64)
set(CMAKE_C_COMPILER loongarch64-unknown-linux-gnu-gcc)
然后这样用:
bash复制cmake -DCMAKE_TOOLCHAIN_FILE=loongarch64.cmake ..
GDB交叉调试需要配合gdbserver:
bash复制# 目标机运行
gdbserver :1234 ./myapp
# 开发机连接
loongarch64-unknown-linux-gnu-gdb ./myapp
(gdb) target remote 龙芯IP:1234
最后说句掏心窝的话:除非有特殊需求,直接用官方预编译工具链真的省心。我后来所有项目都改用预编译版本了,再也不用半夜被编译错误惊醒。把省下的时间用来写代码,它不香吗?