# 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 (過度精簡的) 編譯的流程還有格式 ![image](https://hackmd.io/_uploads/By6ZWYYikl.png) ## 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 ```