当前位置: 首页 > 工具软件 > GNU toolchain > 使用案例 >

Ubuntu安装riscv-gnu-toolchain和riscv-tools

李捷
2023-12-01

GNU toolchain(GNU工具链)是一个包含了由GNU项目所产生的各种编程工具的集合。这些工具形成了一条工具链(串行使用的一组工具),用于开发应用程序和操作系统。riscv-gnu-toolchain与普通gnu-toolchain基本相同,支持riscv32/64位指令集架构。
本文将在Ubuntu-22.04-LTS上编译riscv-gnu-toolchain

一、安装依赖包

sudo apt-get install autoconf 
sudo apt-get install automake 
sudo apt-get install autotools-dev 
sudo apt-get install curl 
sudo apt-get install python3 
sudo apt-get install libmpc-dev 
sudo apt-get install libmpfr-dev 
sudo apt-get install libgmp-dev 
sudo apt-get install gawk 
sudo apt-get install build-essential 
sudo apt-get install bison 
sudo apt-get install flex 
sudo apt-get install texinfo 
sudo apt-get install gperf 
sudo apt-get install libtool 
sudo apt-get install patchutils 
sudo apt-get install bc 
sudo apt-get install zlib1g-dev 
sudo apt-get install libexpat-dev
sudo apt-get install libnewlib-dev
sudo apt-get install device-tree-compiler

二、下载源码

下载riscv-gnu-toolchain

git clone https://github.com/riscv/riscv-gnu-toolchain
cd riscv-gnu-toolchain
git submodule update --init   #递归下载子模块

整个工具链主要包括以下模块:

  • -GCC(GNU C Compiler):通过“预处理-编译-汇编-链接”,将.c文件转换为目标机器上的可执行文件
  • -C运行库:包括glibic, musl,newlib,为C标准库提供函数实现支持,可以根据需求进行自定义修改
  • -Binutils::一组二进制程序处理工具,包括ar(静态库处理),as(汇编器),ld(链接器)等
  • -GDB: 用于进行项目调试,程序运行检查
  • -DejaGnu:程序测试框架,为所有测试提供一个前端支持
  • -qemu:纯软件实现的虚拟化模拟器,几乎可以模拟任何硬件设备。如果不需要该模拟器,可在执行git submodule update --init 命令前将其删除:git rm qemu
  • -spike:RISC-V的一种仿真器,它可以仿真一个或多个hart
  • pk:(proxy kernel)包含了一个boot loader和一个能处理系统调用的代理内核
    由于众所周知的原因,该过程可能持续一到两个小时。当出现如下信息时,表示下载成功,整个项目文件所占空间约1.8GB。
子模组路径 'glibc':检出 '9826b03b747b841f5fc6de2054bf1ef3f5c4bdf3'
子模组路径 'musl':检出 '85e0e3519655220688e757b9d5bfd314923548bd'
子模组路径 'newlib':检出 '415fdd4279b85eeec9d54775ce13c5c412451e08'
子模组路径 'pk':检出 '2efabd3e6604b8a9e8f70baf52f57696680c7855'
子模组路径 'qemu':检出 '823a3f11fb8f04c3c3cc0f95f968fef1bfc6534f'
子模组路径 'riscv-binutils':检出 '20756b0fbe065a84710aa38f2457563b57546440'
子模组路径 'riscv-dejagnu':检出 '4ea498a8e1fafeb568530d84db1880066478c86b'
子模组路径 'riscv-gcc':检出 '5964b5cd72721186ea2195a7be8d40cfe6554023'
子模组路径 'riscv-gdb':检出 '5da071ef0965b8054310d8dde9975037b0467311'
子模组路径 'spike':检出 'a0298a33e7b2091ba8d9f3a20838d96dc1164cac'

此时不要关闭终端。在图形界面进入riscv-gnu-toolchain文件夹,检查子模块的文件夹是否为空。

可能出现的问题及解决方法

1、下载失败
可以选择科学上网,也可选择重试大法。或者选择别的时间点进行下载,亲测北京时间凌晨3点至4点的下载速度很快。
2、提示下载完成,本地文件夹中却显示此文件夹为空
此时不要关闭终端,在riscv-gnu-toolchain文件夹下删除为空的子文件夹,在终端中重新执行git submodule update --init 命令即可。

三、创建安装目录及设置环境变量

sudo mkdir /opt/RISCV/riscv64
sudo chmod -R 777 /opt/RISCV/riscv64 	
sudo vim ~/.bashrc
export RISCV="/opt/RISCV/riscv64"    	#工具链的安装链接路径
export PATH=$PATH:$RISCV/bin 
source ~/.bashrc     					#使此设置永久有效,不然每次打开终端都需要重新设置

四、编译安装riscv-gnu-toolchain

riscv-gnu-toolchain可以编译为以下版本:

  • riscv32-unknown-elf-gcc
  • riscv64-unknown-elf-gcc
  • riscv32-unknown-linux-gnu-gcc
  • riscv64-unknown-linux-gnu-gcc
  • riscv64-multilib-elf-gcc
  • riscv64-linux-multilib-gcc
  • riscv-none-embed-gcc

riscv64-unknown-linux-gnu为前缀表示该版本的工具链是64位架构的Linux版本工具链。注意:此linux不是指当前版本工具链一定要运行在linux操作系统的电脑上,而是是指该GCC工具链会使用Linux的Glibc作为C运行库。
同理,riscv32-unknown-linux-gnu前缀的版本则是32位架构。
riscv64-unknown-elf为前缀表示该版本为非linux(Non-linux)版本的工具链。注意:此Non-Linux不是指当前版本工具链一定不能运行在Linux操作系统的电脑上,而是指该GCC工具链会使用newlib作为C运行库。
同理,riscv32-unknown-elf前缀的版本则是32位架构。
riscv64-multilib-elf为前缀表示该版本为同时支持32位和64位的裸机编译工具链。
riscv64-linux-multilib为前缀表示该版本为同时支持32位和64位的linux版本编译工具链。
riscv-none-embed为前缀版本表示是最新为裸机(bare-metal)嵌入式系统而生成的交叉编译工具链,所谓裸机(bare-metal)是嵌入式领域的一个常见形态,表示不运行操作系统的系统。该版本使用新版本的newlib作为C运行库,并且支持newlib-nano,能够为嵌入式系统生成更加优化的代码体积(Code Size)。

总结: riscv的gcc编译器,分为2大类:

  • 裸机: unknown-elf,none-embed
  • linux: linux
    除了non-embed编译器,对于每一类,如果禁用multilib,那么又分为32位版本和64位版本。如果使能multilib,那么就只有一个版本,但是这个版本工具,可以同时支持32位和64位。

1、编译riscv32-unknown-elf-gcc

cd riscv-gnu-toolchain
mkdir build
cd build
../configure --prefix=/opt/RISCV/riscv64 --with-arch=rv32imc --with-abi=xxx
sudo make -jN

2、编译 riscv64-unknown-elf-gcc

cd riscv-gnu-toolchain
mkdir build
cd build
../configure --prefix=/opt/RISCV/riscv64 --with-arch=rv64imc --with-abi=xxx
sudo make -jN 

3、编译riscv32-unknown-linux-gnu-gcc

cd riscv-gnu-toolchain
mkdir build
cd build
../configure --prefix=/opt/RISCV/riscv32 --with-arch=rv64imc --with-abi=xxx --enable-linux 
sudo make linux -jN

4、编译riscv64-unknown-linux-gnu-gcc

cd riscv-gnu-toolchain
mkdir build
cd build
../configure --prefix=/opt/RISCV/riscv64 --with-arch=rv64imafd --with-abi=lp64d --enable-linux --disable-multilib 
sudo make linux -jN

5、编译riscv64-multilib-elf-gcc

编译multilib版本的gcc,可以同时支持32位和64位

cd riscv-gnu-toolchain
mkdir build
cd build
../configure --prefix=/opt/riscv64-multilib-elf --enable-multilib --target=riscv64-multilib-elf
sudo make -jN

对于riscv64-multilib-elf-gcc编译器,可以通过以下选项,来决定生成的程序是32位版本还是64位版本:

-march=rv32 : 32位版本
-march=rv64 : 64位版本

6、编译 riscv64-linux-multilib-gcc

cd riscv-gnu-toolchain
mkdir build
cd build
../configure --prefix=/opt/riscv-linux-multilib --enable-multilib --target=riscv64-linux-multilib
sudo make -jN

对于riscv64-linux-multilib-gcc编译器,可以通过以下选项,来决定生成的程序是32位版本还是64位版本:

-march=rv32 : 32位版本
-march=rv64 : 64位版本

7、riscv-none-embed-gcc

专门为嵌入式使用的gcc交叉编译工具链。官方网站:https://gnu-mcu-eclipse.github.io/toolchain/riscv/
可以直接下载linux的二进制执行程序,以及windows的安装包。这个一般要搭配GNU MCU eclipse工具一起使用。
因为这个工具,直接提供可执行程序,因此就不介绍了。

8、编译选项的含义

  • –prefix:编译结果安装目录
  • –with-arch:要安装的指令集架构

RISCV指令集采用模块化设计,用户可按需选择指令集。其中基本整数指令集为唯一强制要求实现的指令集。

基本指令集指令数描述
RV32I4732位整数指令集,包含算术、分支、访存指令,32位寻址空间,32个32位寄存器
RV32E47RV32I的子集,用于小型的嵌入式场景,16个32位寄存器
RV64I5964位整数指令集,兼容RV32I,64位寻址空间,32个64位寄存器
RV128I71128位整数指令集,兼容RV32I和RV64I,128位寻址空间,32个128位寄存器
拓展指令集指令数描述
M8乘法(Multiplication)指令集和除法指令集,包括4条乘法、2条除法、2条余数操作指令
A11存储原子(Automic)指令集,包含原子操作指令,如读-修改-写、比较-交换等
F26单精度浮点(Float,32bit)指令集
D26双精度浮点(Double,64bit)指令集,兼容F
C26压缩(Compresses)指令集,指令长度变为16位,目的是减少代码大小

【注:特定组合“IMAFD”被称为“通用(General)”组合,用字母G表示】
其他的扩展指令集还包括:

  • “B”标准扩展:位操作
  • “E”标准扩展:嵌入式
  • “H”特权态架构扩展:支持管理程序(Hypervisor)
  • “J”标准扩展:动态翻译语言
  • “L”标准扩展:十进制浮点
  • “N”标准扩展:用户态中断
  • “P”标准扩展:封装的单指令多数据(Packed-SIMD)指令
  • “Q”标准扩展:四精度浮点
  • –with-abi
    ABI(Application Binary Interface):应用程序二进制接口,描述了应用程序和操作系统之间,一个应用和它的库之间,或者应用的组成部分之间的低接口。ABI涵盖了各种细节,如:

数据类型的大小、布局和对齐;
调用约定(控制着函数的参数如何传送以及如何接受返回值),例如,是所有的参数都通过栈传递,还是部分参数通过寄存器传递;哪个寄存器用于哪个函数参数;通过栈传递的第一个函数参数是最先push到栈上还是最后;
系统调用的编码和一个应用如何向操作系统进行系统调用; 一个完整的操作系统ABI中,目标文件的二进制格式、程序库等等

i即int,l即long,p即pointer(指针),32/64指前面给出的类型是32位还是64位;
f即float,指float型浮点数参数通过浮点数寄存器传递
d即double,指float型和double型浮点数参数通过浮点数寄存器传递

数据模型int字长long字长指针字长
ilp32 / ilp32f / ilp32d32bit32bit32bit
lp64 / lp64f / lp64d32bit64bit64bit
是否需要浮点扩展指令float参数double参数
ilp32 / lp64不需要通过整数寄存器(a0~a1)传递通过整数寄存器(a0~a3)传递
ilp32f / lp64f需要F扩展通过浮点寄存器(fa0~fa1)传递通过整数寄存器(a0~a3)传递
ilp32d / lp64d需要F扩展和D扩展通过浮点寄存器(fa0~fa1)传递通过浮点寄存器(fa0~fa1)传递

浮点参数传递规则只与 --mabi选项有关,与--march选项没有直接关系。但是部分--mabi选项需要浮点寄存器,浮点寄存器是通过浮点扩展指令引入的,这就需要在--march选项中指定浮点扩展。

  • –enable-linux:编译结果在linux环境下运行
  • –disable-multilib:只编译64位程序,不兼容32位
    更多编译选项请使用命令../configure --help查看

9、测试

riscv64-unknown-linux-gnu-gcc -v

出现如下信息则表示安装成功

Using built-in specs.
COLLECT_GCC=riscv64-unknown-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/opt/RISCV/riscv64/libexec/gcc/riscv64-unknown-linux-gnu/11.1.0/lto-wrapper
Target: riscv64-unknown-linux-gnu
Configured with: /home/lihua/riscv-gnu-toolchain/build/../riscv-gcc/configure --target=riscv64-unknown-linux-gnu --prefix=/opt/RISCV/riscv64 --with-sysroot=/opt/RISCV/riscv64/sysroot --with-pkgversion=g --with-system-zlib --enable-shared --enable-tls --enable-languages=c,c++,fortran --disable-libmudflap --disable-libssp --disable-libquadmath --disable-libsanitizer --disable-nls --disable-bootstrap --src=../../riscv-gcc --disable-multilib --with-abi=lp64d --with-arch=rv64imafd --with-tune=rocket --with-isa-spec=2.2 'CFLAGS_FOR_TARGET=-O2   -mcmodel=medlow' 'CXXFLAGS_FOR_TARGET=-O2   -mcmodel=medlow'
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 11.1.0 (g) 

五、编译安装riscv-tools

编译spike

进入spike目录下

cd spike 
mkdir build 
cd build 
../configure --prefix=$RISCV
make
[sudo] make install 						#sudo为可选项

编译pk

进入pk目录下

cd pk
mkdir build
cd build
../configure --prefix=$RISCV --host=riscv64-unknown-linux-gnu
make 
make install

其中–host选项要为与之前构建的交叉编译器相匹配,如果之前构建的交叉编译器为riscv64-unknown-elf-gcc,则该项应设置为riscv64-unknown-elf。默认情况下将生成64位的可执行程序,如果想要生成32位可执行程序,请在configure后面添加--with-arch=rv32i

六、综合测试

编写一个测试程序

#include<stdio.h>
void main(){
	printf("hello world!\n");
}

使用riscv64-unknown-linux-gnu-gcc编译:

riscv64-unknown-linux-gnu-gcc -o hello hello.c -static

使用spike执行可执行文件:

spike pk hello

当屏幕上出现hello world时,则说明全套工具安装成功。

可能出现的问题及解决方法

当安装有多个版本的pk时,执行命令spike pk会报如下错误:

terminate called after throwing an instance of 'std::runtime_error'
  what():  could not open pk (did you misspell it? If VCS, did you forget +permissive/+permissive-off?)

此时则需要我们指定pk的绝对路径:

spike /opt/RISCV/riscv64/bin/pk hello
 类似资料: