9. 本地编译和交叉编译¶
9.1. 本地编译和交叉编译概念¶
本地编译:是指在本地系统上编译代码,目标是生成适用于当前系统架构和操作系统的可执行文件或库。例如,在一台x86架构的Linux机器上编译一个程序,该程序将只能在同样是x86架构的Linux系统上运行。
交叉编译:是指在一个系统上编译代码,交叉编译生成适用于不同架构或操作系统的可执行文件。例如,在x86架构的Linux机器上交叉编译编译一个ARM程序,该程序将只能运行在ARM架构的设备上。
9.2. 板卡本地编译¶
9.2.1. 安装gcc编译工具¶
由于板卡性能和存储空间因素,板卡默认没有安装gcc编译工具,需要使用apt进行安装:
1 2 3 | #安装编译工具
sudo apt update
sudo apt install gcc
|
安装完成后可以查看gcc的版本,以riscv核Ubuntu系统为例:
1 2 3 4 5 6 7 8 9 10 11 12 | #查看版本
gcc -v
#信息输出如下
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/riscv64-linux-gnu/11/lto-wrapper
Target: riscv64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 11.4.0-1ubuntu1~22.04' --with-bugurl=file:///usr/share/doc/gcc-11/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-11 --program-prefix=riscv64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libitm --disable-libquadmath --disable-libquadmath-support --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --disable-multilib --with-arch=rv64gc --with-abi=lp64d --enable-checking=release --build=riscv64-linux-gnu --host=riscv64-linux-gnu --target=riscv64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=4
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04)
|
可见,gcc的版本为11.4.0,框架为riscv64。
9.2.2. 编译测试¶
简单编译一个helloworld程序,创建helloworld.c并添加以下内容:
1 2 3 4 5 6 | #include <stdio.h>
int main()
{
printf("Hello, World!");
return 0;
}
|
进行编译:
1 2 | #编译
gcc helloworld.c -o helloworld
|
查看编译出来的helloworld信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #file命令查看信息
file helloworld
#信息输出如下
helloworld: ELF 64-bit LSB pie executable, UCB RISC-V, RVC, double-float ABI, version 1 (SYSV), dynamically linked,
interpreter /lib/ld-linux-riscv64-lp64d.so.1, BuildID[sha1]=c774eed0ebef69d495b5381268246fd3f3770974, for GNU/Linux 4.15.0, not stripped
#ldd命令查看信息
ldd helloworld
#信息输出如下
linux-vdso.so.1 (0x0000003fbb655000)
libc.so.6 => /lib/riscv64-linux-gnu/libc.so.6 (0x0000003fbb518000)
/lib/ld-linux-riscv64-lp64d.so.1 (0x0000003fbb657000)
|
可以看到编译出来的程序运行环境是riscv64的,并且依赖系统一些库文件。
运行测试:
1 2 3 4 5 | #运行
./helloworld
#信息输出如下
Hello, World!
|
9.3. 服务器交叉编译¶
由于板卡性能优先,需要编译大型项目的时候如果还在板卡本地编译,那么就需要很长的时间,而且很有可能会编译失败,那么这时就需要服务器进行交叉编译,编译出可在板卡上运行的程序。
9.3.1. 获取交叉编译工具链¶
可以通过GitHub仓库获取或者下载网盘资料/7-SDK源码压缩包/host-tools.tar.gz压缩包。
1 2 3 4 5 | #通过github获取
git clone https://github.com/sophgo/host-tools --depth=1
#通过网盘获取
tar xvf host-tools.tar.gz
|
9.3.2. 查看交叉编译工具链¶
1 2 3 4 5 6 | ls host-tools/gcc/
#信息输出如下
gcc-linaro-6.3.1-2017.05-x86_64_aarch64-elf riscv64-elf-x86_64
gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu riscv64-linux-musl-x86_64
gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf riscv64-linux-x86_64
|
host-tools/gcc目录下有ARM和riscv的编译工具链,需要通过板卡确认使用的是哪个编译工具链:
1 2 3 4 5 | #查看内核版本
cat /proc/version
#信息输出如下
Linux version 5.10.4-tag- (guest@dev107) (riscv64-unknown-linux-musl-gcc (Xuantie-900 linux-5.10.4 musl gcc Toolchain V2.6.1 B-20220906) 10.2.0, GNU ld (GNU Binutils) 2.35) #1 PREEMPT Mon Aug 12 06:20:54 UTC 2024
|
可见,当前板卡使用的是riscv64-unknown-linux-musl-gcc,对应riscv64-linux-musl-x86_64。
查看编译工具链目录,以riscv64-linux-musl-x86_64为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #查看
ls host-tools/gcc/riscv64-linux-musl-x86_64/bin/
#信息输出如下
riscv64-unknown-linux-musl-addr2line riscv64-unknown-linux-musl-gcov-tool
riscv64-unknown-linux-musl-ar riscv64-unknown-linux-musl-gdb
riscv64-unknown-linux-musl-as riscv64-unknown-linux-musl-gdb-add-index
riscv64-unknown-linux-musl-c++ riscv64-unknown-linux-musl-gprof
riscv64-unknown-linux-musl-c++filt riscv64-unknown-linux-musl-ld
riscv64-unknown-linux-musl-cpp riscv64-unknown-linux-musl-ld.bfd
riscv64-unknown-linux-musl-elfedit riscv64-unknown-linux-musl-lto-dump
riscv64-unknown-linux-musl-g++ riscv64-unknown-linux-musl-nm
riscv64-unknown-linux-musl-gcc riscv64-unknown-linux-musl-objcopy
riscv64-unknown-linux-musl-gcc-10.2.0 riscv64-unknown-linux-musl-objdump
riscv64-unknown-linux-musl-gcc-ar riscv64-unknown-linux-musl-ranlib
riscv64-unknown-linux-musl-gcc-nm riscv64-unknown-linux-musl-readelf
riscv64-unknown-linux-musl-gcc-ranlib riscv64-unknown-linux-musl-size
riscv64-unknown-linux-musl-gcov riscv64-unknown-linux-musl-strings
riscv64-unknown-linux-musl-gcov-dump riscv64-unknown-linux-musl-strip
|
bin目录下就是我们需要的交叉编译工具链了。
9.3.3. 编译测试¶
简单编译一个helloworld程序,创建helloworld.c并添加以下内容:
1 2 3 4 5 6 | #include <stdio.h>
int main()
{
printf("Hello, World!");
return 0;
}
|
进行编译,如果是 riscv 需要指定扩展指令集rv64gcv0p7_xthead,如果是 ARM 则不需要。
1 2 | #编译
host-tools/gcc/riscv64-linux-musl-x86_64/bin/riscv64-unknown-linux-musl-gcc helloworld.c -o helloworld -march=rv64imafdcvxthead -mcmodel=medany -mabi=lp64d
|
参数说明如下:
-march:定义了编译器应生成的指令集。
rv64imafdcvxthead:
- 其中:
rv64: 指定使用RISC-V 64位指令集架构。
i: 基本整数指令集。
m: 整数乘法和除法指令集。
a: 原子指令集。
f: 单精度浮点指令集。
d: 双精度浮点指令集。
c: 压缩指令集(C扩展)。
v: 向量指令集(V扩展)。
xthead: 这是一个扩展标志,通常指定特定的自定义指令集扩展或处理器特性。
-mcmodel: 指定代码模型,决定了生成代码的内存布局和地址空间。
medany: RISC-V的一种代码模型,表示中等大小的代码模型,允许程序在更大范围内使用任何地址。
-mabi:指定应用程序二进制接口,影响数据类型的对齐、调用约定、以及数据结构布局等。
lp64d
- 其中:
lp64: 指64位的ABI,指指针(p)、长整型(l)和指针所占的位数为64位,整数为32位。
d: 表示使用双精度浮点数的ABI。
提示
riscv如果不指定扩展指令集是无法在板卡运行的,原因是缺运行库,读者可自行查看程序信息和测试。
查看编译出来的helloworld信息:
1 2 3 4 5 6 7 8 9 10 11 12 | #file命令查看信息
file helloworld
#信息输出如下
helloworld: ELF 64-bit LSB executable, UCB RISC-V, version 1 (SYSV), dynamically linked,
interpreter /lib/ld-musl-riscv64v_xthead.so.1, with debug_info, not stripped
#ldd命令查看信息
ldd helloworld
#信息输出如下
not a dynamic executable
|
可以看到编译出来的程序运行环境是riscv的,并且只依赖/lib/ld-musl-riscv64v_xthead.so.1,和前面在板卡编译出来的可执行程序不一样。
传到板卡并运行测试:
1 2 3 4 5 | #运行
./helloworld
#信息输出如下
Hello, World!
|