# Build RISC-V GNU Tool Chain
:::info
**Latest Updated Date:** March 08, 2025
:::
本教學文章為隨手紀錄操作流程,有錯誤或不詳盡之處請見諒。
大量圖片摘自參考資料,我轉載的文字及圖片著作權歸於參考資料之作者所有。
本教學文章針對 [ RISC-V ( Reduced Instruction Set Computer-V )](https://zh.wikipedia.org/zh-tw/RISC-V) ) RV32IM 指令集架構建構 ( build ) RISC-V Tool Chain
> RV32:RISC-V 32bits
> RV32I:最基礎 ( Base ) 整數指令集,其它指令集都可視為這個指令集的擴充
> RV32M:乘法、除法指令集擴充 ( Extension )
本篇教學文章針對 [**RISC-V 官方 Tool Chain**](https://github.com/riscv-collab/riscv-gnu-toolchain) 建構流程所撰寫
## 什麼是 Tool Chain?
參考資料:[你所不知道的 C 語言:編譯器和最佳化原理篇](https://hackmd.io/VerfJi2ZSIO0RbgeL2ppGQ?view) - HackMD
Copyright (**慣C**) 2015, 2016, 2017 [宅色夫](http://wiki.csie.ncku.edu.tw/User/jserv)
假設有一高階程式語言檔案。
- hello.c:
```c
int main() { return 1; }
```
如果要在 GNU/Linux 的作業系統環境中,將高階程式語言檔案 ( 如 hello.c ) 編譯成可執行檔,需要在終端機上打入:
- GNU/Linux 終端機:
```bash
gcc -o hello hello.c
```
高階程式語言檔案需要經過一系列的操作才可以被轉化為 GNU/Linux 作業系統環境中的可執行檔 ( 如 .elf 檔案 ) 。
- Compilation flow (過度精簡的) 編譯的流程還有格式

## GNU Tool Chain 包括
gcc : GNU compiler collection
as : GNU assembler
ld : GNU linker
gdb : GNU debugger
## 初探 RISC-V Tool Chain
由上可知,Tool Chain 是一系列工具的組合。而 RISC-V Tool Chain 則是可將高階程式語言檔案轉化為 RISV-V 硬體架構的可執行檔工具組合。
RISC-V 官方維護的 Tool Chain:
https://github.com/riscv-collab/riscv-gnu-toolchain
該 Tool CHain 包括 gcc 。而 gcc 可視為一種 C、C++ cross-compiler。
> cross-compiler:在特定硬體架構下的作業系統環境,將高階程式語言轉化為另一種硬體架構的可執行檔之編譯器
像是廢話的結論:而 RISC-V Tool Chain 的目標指令集架構為:RISC-V 。
## 建構 RISC-V Tool CHain 流程
- 本教學文章的操作流程基於 x86 指令集架構上的 GNU/Linux ( Ubuntu ) 作業系統環境
參考資料:
1. [Build riscv-gnu-toolchain](https://hackmd.io/@yrr-itri/Hk3uMlzI3) - HackMD
Copyright [YT Cheng](https://hackmd.io/@yrr-itri)
2. [Getting Started with the RISC-V Open Source GNU Toolchain](https://privateisland.tech/dev/rv-getting-started) - company website
Copyright [privateisland](https://privateisland.tech/)
我推薦更新以下工具:
``` Bash
sudo apt-get upgrade
```
我推薦安裝以下工具:
``` Bash
sudo apt-get install vim tree git gcc make
```
---
## **建構 Tool Chain 正式流程:**
## Step 0, Install packages needed
```Bash
sudo apt-get install autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev ninja-build
```
## Step 1, Clone from riscv-gnu-toolchain
在 Ubuntu 的目錄:/home/<user name of yours>
```Bash
$ git clone --recursive https://github.com/riscv/riscv-gnu-toolchain
Cloning into 'riscv-gnu-toolchain'...
...
```
位置:/home/vboxuser ( 以我為例 )
下載完畢進行測試:
```Bash!
$ ls
binutils configure contrib gcc glibc linux-headers Makefile.in newlib qemu regression spike
uclibc-ng configure.ac dejagnu gdb LICENSE llvm musl pk README.md scripts test
```
:::danger
Tool Chain 約 6.4 GB,下載時間依電腦 CPU 速度而定。
以我為例,Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz 3.41 GHz 下載長達 <font color="#f00">1.5 小時</font>。
:::
請確保硬碟可用空間大於 15 GB,若空間不夠請自行參閱:[對VirtualBox內的Ubuntu虛擬機,擴充硬碟空間-一篇寫了8小時的技術文章](https://medium.com/@newpage0720/%E5%9C%A8virtualbox%E5%85%A7%E7%9A%84ubuntu%E8%99%9B%E6%93%AC%E6%A9%9F-%E5%9B%BA%E5%AE%9A%E5%AE%B9%E9%87%8F%E7%A1%AC%E7%A2%9F%E8%BD%89%E5%8B%95%E6%85%8B%E9%85%8D%E7%BD%AE%E7%A1%AC%E7%A2%9F-%E8%88%87%E6%93%B4%E5%85%85%E7%A1%AC%E7%A2%9F%E7%A9%BA%E9%96%93-6efe6b1abcb3) - Medium
Copyright [陳國仁](https://medium.com/@newpage0720)
## Step 2, Create a installation dir and add it to PATH
```Bash
cd riscv-gnu-toolchain/
```
```Bash
mkdir build; cd build
```
## Step 3, Generate Makefile according to target system
```Bash
$ ../configure --help | grep abi
--with-abi=lp64d Sets the base RISC-V ABI, defaults to lp64d
```
```Bash
$ ../configure --prefix=/opt/riscv32 --with-arch=rv32imzicsr --with-abi=ilp32
checking for gcc... gcc
...
config.status: creating Makefile
config.status: creating scripts/wrapper/awk/awk
config.status: creating scripts/wrapper/sed/sed
```
設定解析:
- --prefix= 指定 make 好的檔案被放置的位置。
--with-arch= 指定指令集架構擴充 ( 例如 rv32imzicsr ),編譯好的指令將全部限縮在這個範圍。
- --with-abi= 指定 ilp32 這 1 個 ABI,所有的 int、long、pointer 皆為 32-bits。
> ABI ( Application Binary Interface ) 字面上定義為 2 個 binary ( 通常為執行檔 ) 檔案互動的介面,介面規範編譯器和連結器需遵循這些規則來編譯您的程式,包括程式中的函數、函數參數命名規則、函數參數傳遞方式等,以便使其正常運作。連結到同一執行檔的任何程式碼都必須符合相同的 ABI。而 ABI 依賴於硬體架構而定。
最簡單理解的方法為將 ABI 與 API ( Application Programming Interface ) 進行比較。兩者非常相似,可將 ABI 其視為 API 的編譯版本(或機器語言層級的 API),當您編寫高階語言程式碼時,您可以透過 API 存取該程式庫。程式碼編譯完成後,您的應用程式就會遵循 ABI 存取外部函式庫中的二進位資料。ABI 定義了編譯後的應用程式用來存取外部函式庫的結構和方法(就像 API 一樣)。
延伸閱讀:[What is an application binary interface (ABI)?](https://stackoverflow.com/questions/2171177/what-is-an-application-binary-interface-abi) - StackOverflow
## Step 4, After makefile is done, build toolchain
```
sudo make -j4
```
> 設定解析:
-j<number of threads>
建議使用硬體多執行緒來加快 make 速度,而執行緒數量則取決於電腦硬體而定。
:::danger 在 Tool Chain 的 GNU Make 設定完成之後,我們就可以 make 這個 Tool Chain 了,所有 make 好的檔案將自動被放置於: /opt/riscv32/
make 需耗費大量時間,make 時間依電腦 CPU 速度而定。
以我為例,我耗費了 2.5 小時。
:::
## Step 5, Check the toolchain
```Bash
$ ls
build-binutils-newlib build-gcc-newlib-stage2 build-newlib config.log install-newlib-nano scripts
build-gcc-newlib-stage1 build-gdb-newlib build-newlib-nano config.status Makefile stamps
```
```Bash
$ cd /opt/riscv32
$ tree -L 2 -d
.
├── bin
├── include
│ ├── gdb
│ └── sim
├── lib
│ ├── bfd-plugins
│ └── gcc
├── libexec
│ └── gcc
├── riscv32-unknown-elf
│ ├── bin
│ ├── include
│ └── lib
└── share
├── gcc-14.2.0
├── gdb
├── info
├── locale
└── man
```
建立「暫時的」系統環境變數:
```Bash
export PATH=/opt/riscv32/bin:$PATH
```
> 設定解析:
PATH=<The path of yours executable file>
依照上述步驟,「riscv32-unknwon-elf」這 1 個可執行檔將被安裝於「/opt/riscv32/bin」目錄內。
- 這條指令只會影響當前終端機會話 ( Terminal session ) ,如果關閉終端機或重新開機,設定就會消失。若要讓它永久生效,可以將這行指令加到 ~/.bashrc 或 ~/.bash_profile(對於 Bash 使用者),或者 ~/.zshrc(對於 Zsh 使用者):
### 如何永久修改 PATH?
```Bash
echo 'export PATH=/opt/riscv32/bin:$PATH' >> ~/.bashrc
```
需重新開啟新的終端機,待設定生效。若不重開終端機,可運行:
```Bash
source ~/.bashrc
```
### 檢查 Tool Chain 資訊:
```Bash
$ mkdir -p ~/Projects/riscv; cd ~/Projects/riscv
$ source /opt/riscv32/env-riscv32
$ riscv32-unknown-elf-gcc --version
riscv32-unknown-elf-gcc () 14.2.0
...
$ riscv32-unknown-elf-objcopy --version
GNU objcopy (GNU Binutils) 2.43.1
...
```
### 檢查 Tool Chain 中的 Compiler 與 binutils:
```Bash
$ riscv32-unknown-elf-gcc -dumpmachine
riscv32-unknown-elf
$ riscv32-unknown-elf-gcc -print-sysroot
/opt/riscv32/riscv32-unknown-elf
$ riscv32-unknown-elf-gcc -print-libgcc-file-name
/opt/riscv32/lib/gcc/riscv32-unknown-elf/14.2.0/libgcc.a
$ riscv32-unknown-elf-gcc -print-search-dirs
install: /opt/riscv32/lib/gcc/riscv32-unknown-elf/14.2.0/
programs: =/opt/riscv32/libexec/gcc/riscv32-unknown-elf/14.2.0/:/opt/riscv32/libexec/gcc/riscv32-unknown-elf/14.2.0/:/opt/riscv32/libexec/gcc/riscv32-unknown-elf/:/opt/riscv32/lib/gcc/riscv32-unknown-elf/14.2.0/:/opt/riscv32/lib/gcc/riscv32-unknown-elf/:/opt/riscv32/lib/gcc/riscv32-unknown-elf/14.2.0/../../../../riscv32-unknown-elf/bin/riscv32-unknown-elf/14.2.0/:/opt/riscv32/lib/gcc/riscv32-unknown-elf/14.2.0/../../../../riscv32-unknown-elf/bin/
libraries: =/opt/riscv32/lib/gcc/riscv32-unknown-elf/14.2.0/:/opt/riscv32/lib/gcc/riscv32-unknown-elf/14.2.0/../../../../riscv32-unknown-elf/lib/riscv32-unknown-elf/14.2.0/:/opt/riscv32/lib/gcc/riscv32-unknown-elf/14.2.0/../../../../riscv32-unknown-elf/lib/:/opt/riscv32/riscv32-unknown-elf/lib/riscv32-unknown-elf/14.2.0/:/opt/riscv32/riscv32-unknown-elf/lib/:/opt/riscv32/riscv32-unknown-elf/usr/lib/riscv32-unknown-elf/14.2.0/:/opt/riscv32/riscv32-unknown-elf/usr/lib/
```
檢查是否有 newlib-nano library:
```Bash
$ ls /opt/riscv32/riscv32-unknown-elf/lib
crt0.o libc.a libg.a libgloss_nano.a libm.a libnosys.a libsim.a libstdc++.a-gdb.py libstdc++exp.la libsupc++.a nano.specs semihost.specs
ldscripts libc_nano.a libgloss.a libg_nano.a libm_nano.a libsemihost.a libstdc++.a libstdc++exp.a libstdc++.la libsupc++.la nosys.specs sim.specs
```
檢查 ToolChain 可搭配的 march 以及 mabi 兩個參數組合指令運行結果:
```Bash
$ riscv64-unknown-elf-gcc --print-multi-lib
.;
rv32ec/ilp32e;@march=rv32ec@mabi=ilp32e
rv32ec_zba_zbb/ilp32e;@march=rv32ec_zba_zbb@mabi=ilp32e
rv32eac/ilp32e;@march=rv32eac@mabi=ilp32e
rv32eac_zba_zbb/ilp32e;@march=rv32eac_zba_zbb@mabi=ilp32e
rv32emc/ilp32e;@march=rv32emc@mabi=ilp32e
rv32emc_zba_zbb/ilp32e;@march=rv32emc_zba_zbb@mabi=ilp32e
rv32emac/ilp32e;@march=rv32emac@mabi=ilp32e
rv32emac_zba_zbb/ilp32e;@march=rv32emac_zba_zbb@mabi=ilp32e
rv32ic/ilp32;@march=rv32ic@mabi=ilp32
rv32ic_zba_zbb/ilp32;@march=rv32ic_zba_zbb@mabi=ilp32
rv32iac/ilp32;@march=rv32iac@mabi=ilp32
rv32iac_zba_zbb/ilp32;@march=rv32iac_zba_zbb@mabi=ilp32
rv32imc/ilp32;@march=rv32imc@mabi=ilp32
rv32imc_zba_zbb/ilp32;@march=rv32imc_zba_zbb@mabi=ilp32
rv32imac/ilp32;@march=rv32imac@mabi=ilp32
rv32imac_zba_zbb/ilp32;@march=rv32imac_zba_zbb@mabi=ilp32
rv32imfc/ilp32f;@march=rv32imfc@mabi=ilp32f
rv32imfc_zba_zbb/ilp32f;@march=rv32imfc_zba_zbb@mabi=ilp32f
rv32imafc/ilp32f;@march=rv32imafc@mabi=ilp32f
rv32imafc_zba_zbb/ilp32f;@march=rv32imafc_zba_zbb@mabi=ilp32f
rv32imfdc/ilp32d;@march=rv32imfdc@mabi=ilp32d
rv32imfdc_zba_zbb/ilp32d;@march=rv32imfdc_zba_zbb@mabi=ilp32d
rv32imafdc/ilp32d;@march=rv32imafdc@mabi=ilp32d
rv32imafdc_zba_zbb/ilp32d;@march=rv32imafdc_zba_zbb@mabi=ilp32d
rv64ic/lp64;@march=rv64ic@mabi=lp64
rv64ic/lp64/compact;@march=rv64ic@mabi=lp64@mcmodel=compact
rv64ic_zba_zbb/lp64;@march=rv64ic_zba_zbb@mabi=lp64
rv64ic_zba_zbb/lp64/compact;@march=rv64ic_zba_zbb@mabi=lp64@mcmodel=compact
rv64iac/lp64;@march=rv64iac@mabi=lp64
rv64iac/lp64/compact;@march=rv64iac@mabi=lp64@mcmodel=compact
rv64iac_zba_zbb/lp64;@march=rv64iac_zba_zbb@mabi=lp64
rv64iac_zba_zbb/lp64/compact;@march=rv64iac_zba_zbb@mabi=lp64@mcmodel=compact
rv64imc/lp64;@march=rv64imc@mabi=lp64
rv64imc/lp64/compact;@march=rv64imc@mabi=lp64@mcmodel=compact
rv64imc_zba_zbb/lp64;@march=rv64imc_zba_zbb@mabi=lp64
rv64imc_zba_zbb/lp64/compact;@march=rv64imc_zba_zbb@mabi=lp64@mcmodel=compact
rv64imac/lp64;@march=rv64imac@mabi=lp64
rv64imac/lp64/compact;@march=rv64imac@mabi=lp64@mcmodel=compact
rv64imac_zba_zbb/lp64;@march=rv64imac_zba_zbb@mabi=lp64
rv64imac_zba_zbb/lp64/compact;@march=rv64imac_zba_zbb@mabi=lp64@mcmodel=compact
rv64imfc/lp64f;@march=rv64imfc@mabi=lp64f
rv64imfc/lp64f/compact;@march=rv64imfc@mabi=lp64f@mcmodel=compact
rv64imfc_zba_zbb/lp64f;@march=rv64imfc_zba_zbb@mabi=lp64f
rv64imfc_zba_zbb/lp64f/compact;@march=rv64imfc_zba_zbb@mabi=lp64f@mcmodel=compact
rv64imafc/lp64f;@march=rv64imafc@mabi=lp64f
rv64imafc/lp64f/compact;@march=rv64imafc@mabi=lp64f@mcmodel=compact
rv64imafc_zba_zbb/lp64f;@march=rv64imafc_zba_zbb@mabi=lp64f
rv64imafc_zba_zbb/lp64f/compact;@march=rv64imafc_zba_zbb@mabi=lp64f@mcmodel=compact
rv64imfdc/lp64d;@march=rv64imfdc@mabi=lp64d
rv64imfdc/lp64d/compact;@march=rv64imfdc@mabi=lp64d@mcmodel=compact
rv64imfdc_zba_zbb/lp64d;@march=rv64imfdc_zba_zbb@mabi=lp64d
rv64imfdc_zba_zbb/lp64d/compact;@march=rv64imfdc_zba_zbb@mabi=lp64d@mcmodel=compact
rv64imafdc/lp64d;@march=rv64imafdc@mabi=lp64d
rv64imafdc/lp64d/compact;@march=rv64imafdc@mabi=lp64d@mcmodel=compact
rv64imafdc_zba_zbb/lp64d;@march=rv64imafdc_zba_zbb@mabi=lp64d
rv64imafdc_zba_zbb/lp64d/compact;@march=rv64imafdc_zba_zbb@mabi=lp64d@mcmodel=compact
```