开始之前
本章目标是把开发环境与上板通道真正打通:你能在电脑上安装并使用 RuyiSDK 交叉工具链,把 RevyOS 烧到荔枝派 4A,用串口或 SSH 登录板子,并理解为什么必须用交叉编译才能生成板子可执行的程序。学完本章,你应当能在主机上交叉编出一份 RISC-V 架构的 CoreMark,并用 file 确认产物架构正确。
整章可以看成一条链:先认清板子与工具(1.1),再把系统烧进去并打通登录与传文件的通道(1.2),最后弄清交叉编译并用 Makefile 编出 CoreMark(1.3)。
你需要准备什么
电脑
Linux x86_64(推荐 Ubuntu 22.04+)。可联网,磁盘至少留 10GB。
荔枝派 4A
一块开发板。配套:电源适配器、USB 数据线(能传数据)、3.3V USB-TTL 串口模块、网线或 Wi-Fi。
软件
课程指定的 RevyOS 镜像、RuyiSDK(命令入口是 ruyi)、RISC-V 交叉编译工具链。安装步骤在 1.1–1.2。
本章你会学到什么
1.1 荔枝派 4A 与 RuyiSDK
认清板子接口;安装 ruyi;验证交叉编译器能编出 RISC-V 程序。
1.2 烧录、开发通道与一键准备/一键编译
把系统写到板子上;打通串口、SSH、SCP;掌握一键准备与一键编译的用法。
1.3 交叉编译、Makefile 与 CoreMark
弄清本机编译与交叉编译的差别;用 Makefile 交叉编出 CoreMark;用 file 确认产物是 RISC-V。
本章术语:先说清,再往下
下面这些词会在本章反复出现。先扫一遍,知道「它是什么、为什么需要它」;读到再见到就不慌,也可以随时翻回这一页。它们不是堆砌——每引入一个词,都是因为我们到了必须说清那一步的关口。
| 术语 | 是什么 | 为什么需要它 |
|---|---|---|
| 指令集 | CPU 认识的机器指令清单 | 决定一种 CPU 能执行哪些操作 |
| x86_64 / riscv64 | 两种不同指令集 | 电脑和板子各用一套,程序不能互换 |
| RISC-V | 开放的指令集架构 | 本课板子的 CPU 用它 |
| RevyOS | 面向 RISC-V 的 Linux 发行版 | 烧进板子、跑在板子上的系统 |
| 交叉编译 | 在一台机器上编出另一架构的程序 | 电脑编出板子可运行的 RISC-V 程序 |
| 工具链 | 编译器 + 链接器 + 库的集合 | 把源码一步步变成可执行文件 |
| 三元组(target triple) | 「CPU-厂商-系统」的简写 | 告诉编译器「给谁编」 |
| ELF | 可执行文件的一种容器格式 | file 靠它读出「这是什么架构」 |
| 镜像 | 整套系统的打包 | 烧录的对象 |
| 烧录 | 把镜像按分区写入板子存储 | 给板子装系统 |
| UART / 串口 | 逐字节收发的物理接口 | 本地调试、看开机日志 |
| SSH | 加密的远程登录通道 | 日常登录板子敲命令 |
| SCP | 复用 SSH 传文件 | 电脑与板子之间拷程序 |
| 虚拟环境 | ruyi venv 建的开发环境 | 自动配好工具链路径与 sysroot |
| sysroot | 目标系统的运行库目录 | 链接时找 RISC-V 版 C 库 |
| CoreMark | 测处理器算力的基准程序 | 用一份真程序验证整条工具链通没通 |
| Makefile | 描述编译规则的文本 | 敲一个 make 就按规则编译 |
荔枝派 4A 与 RuyiSDK
认识荔枝派 4A
荔枝派 4A 是本课用的 RISC-V 开发板:一块带 CPU、内存、存储接口和排针的电路板,用来跑 Linux、接传感器和执行器。
指令集是 CPU 认识的机器指令清单——规定「加、跳、读内存」等操作怎么编码成二进制。电脑常见 x86_64 指令集;荔枝派 4A 跑的是 riscv64 指令集。两边指令编码不同,所以电脑上用普通 gcc 编好的程序,不能直接丢到板子上跑。
RISC-V 是一种开放的指令集架构:规范公开,任何人可以做兼容芯片。本课板子上的 Linux 系统是 RevyOS——面向 RISC-V 板子的 Linux 发行版。
动手前先在板子上标出:电源口、串口排针、网口、启动介质(eMMC / SD)。串口模块必须是 3.3V 电平——电平是引脚高低电压的约定;5V 可能损坏板子。
| 项目 | 要求 | 检查方式 |
|---|---|---|
| 电脑系统 | Linux x86_64 | uname -a |
| 开发板 | 荔枝派 4A | 核对板卡丝印与包装 |
| USB 线 | 能传数据(不只充电) | 换已知数据线试 |
| 串口模块 | 3.3V USB-TTL | 看模块规格丝印 |
| 网络 | 能访问 RuyiSDK 软件源 | 浏览器或连通性测试 |
| 基础命令 | curl / wget、sha256sum、file | command -v curl |
· 部分 USB-C 线只供电、不传数据 → 电脑认不出设备时先换线
· 串口电平必须 3.3V → 5V 可能损坏板卡
· 工具链前缀选
linux-gnu(跑 Linux 的程序)→ unknown-elf 是裸机工具链,本课不用
安装 RuyiSDK
RuyiSDK 是面向 RISC-V 开发的工具包集合;命令入口叫 ruyi,用来查包、装工具链、查设备支持。真正把 C 代码编成机器码的是里面的 GCC(GNU 编译器)。关系可以记成:ruyi 管「装什么」,GCC 管「怎么编」。
三元组(target triple)是编译器目标平台的简写,格式大致是「CPU-厂商-系统」。本课统一用 riscv64-ruyisdk-linux-gnu(经 RuyiSDK 的 gnu-ruyisdk 提供):意思是「为 64 位 RISC-V CPU、跑 Linux、用 GNU 用户态约定」生成程序。
把三元组从左到右拆开看,每一段都在说一件事:
| 字段 | 含义 | 本课取值 |
|---|---|---|
| CPU | 给哪种指令集生成代码 | riscv64(64 位 RISC-V) |
| 厂商/来源 | 谁提供的这套约定 | ruyisdk |
| 系统 | 跑在什么系统上 | linux |
| 用户态 | 用哪套库与 ABI | gnu(GNU / glibc) |
把用户态一段换成 elf(如 riscv64-unknown-elf),就变成裸机工具链——没有 Linux 的加载与运行库,编出的程序跑不了本课这样的 Linux 用户程序。
安装包管理器本身请以 RuyiSDK 官方安装文档 为准。官方推荐使用预编译二进制;对于已配置 Python 环境的 x86 Linux 主机,也可以通过 PyPI 安装。下面按 PyPI 路径写出本课步骤。
- 1记录电脑环境
在 x86 Linux 上执行uname -m,确认输出为x86_64。 - 2安装 Ruyi 包管理器
预编译二进制的下载与放置见官方文档。本课在已配置 Python 的 x86 Linux 上走 PyPI:python3 -m pip install --user ruyi
若pip把可执行文件装到~/.local/bin,请确认该目录已在PATH中(可把export PATH="$HOME/.local/bin:$PATH"写入~/.bashrc后source ~/.bashrc)。其它发行版安装方式见官方文档。 - 3PATH 检查与版本验证
command -v ruyi应给出绝对路径(例如/home/你的用户名/.local/bin/ruyi);ruyi --version应打印版本号(本课验收样例主机为Ruyi 0.46.0,你机器上的次版本可以更新,但必须能运行)。 - 4更新并安装 gnu-ruyisdk 工具链
ruyi update,再ruyi install gnu-ruyisdk。 - 5创建并激活虚拟环境
(目录自定,下文以家目录为例):ruyi venv -t gnu-ruyisdk manual venv-gnu-ruyisdk . ~/venv-gnu-ruyisdk/bin/ruyi-activate
每次新开终端都要重新激活。磁盘紧张时可加--without-sysroot(仍能交叉编译本课 CoreMark)。 - 6确认交叉编译器
riscv64-ruyisdk-linux-gnu-gcc -v;riscv64-ruyisdk-linux-gnu-gcc -dumpmachine应打印riscv64-ruyisdk-linux-gnu。
# 以下均在 x86 Linux 上执行 $ uname -m x86_64 $ python3 -m pip install --user ruyi $ export PATH="$HOME/.local/bin:$PATH" # 若尚未写入 shell 配置 $ command -v ruyi /home/你的用户名/.local/bin/ruyi $ ruyi --version Ruyi 0.46.0 # …版权与许可信息略… $ ruyi update $ ruyi install gnu-ruyisdk $ ruyi venv -t gnu-ruyisdk manual venv-gnu-ruyisdk $ . ~/venv-gnu-ruyisdk/bin/ruyi-activate $ riscv64-ruyisdk-linux-gnu-gcc -dumpmachine riscv64-ruyisdk-linux-gnu
最小编译验证
写一个空程序,用交叉编译器编一下,再用 file 看产物是不是 RISC-V。ELF 是 Linux 上可执行文件与目标文件的常见容器格式;file 会读出里面的架构字段。
$ printf 'int main(void) { return 0; }\n' > mini.c $ riscv64-ruyisdk-linux-gnu-gcc mini.c -o mini-riscv $ file mini-riscv mini-riscv: ELF 64-bit LSB executable, UCB RISC-V, ...
在电脑上直接 ./mini-riscv 会失败——指令集不同。验收看 file 输出里有 RISC-V 字样即可。
ruyi 已安装且 PATH 可用 · 版本记录 · 三元组 riscv64-ruyisdk-linux-gnu · 最小 RISC-V 可执行文件与 file 日志。
烧录、开发通道与一键准备/一键编译
烧录系统
烧录是把系统镜像按分区写入板子存储(本课用板载 eMMC)。镜像里通常有:引导程序(U-Boot)、启动分区(内核与设备树等)、根文件系统(RevyOS 用户空间)。
本课指定组合(与验收样机一致):
- 硬件:Sipeed LicheePi 4A 16G(设备树 model 为
Sipeed Lichee Pi 4A 16G) - 系统:RevyOS 20251226(板端
/etc/revyos-release中RELEASE_ID=20251226、BOARD_NAME=lpi4a) - 主路径:用 RuyiSDK 的
ruyi device provision交互式下载并写入(底层走 fastboot;包索引中对应revyos-sipeed-lpi4a+uboot-revyos-sipeed-lpi4a-16g)
对照资料(排障与手工备用时查阅):
- RuyiSDK Support Matrix · LicheePi 4A / RevyOS(当前 good 记录即 20251226;含镜像目录与手工 fastboot 命令)
- Sipeed 官方烧录文档(BOOT 键进烧录模式、接线说明)
环境准备
- 主机已按 1.1 装好
ruyi,并能ruyi --version。 - 主机安装
fastboot(Debian/Ubuntu 示例:sudo apt install -y fastboot或包名android-tools-fastboot,以发行版为准)。 - USB-C 数据线能传数据(仅充电线无法进烧录模式);另备 USB-UART 串口线(3.3V)便于看首次启动日志。
- 板子供电充足;烧录会覆盖 eMMC 上的系统,先备份需要保留的文件。
用 ruyi device provision 烧录(主路径)
- 1更新索引并启动向导
在主机执行ruyi update,再ruyi device provision。按提示确认后继续。 - 2选择设备与规格
设备选 Sipeed LicheePi 4A;内存规格选 16G(8G 板不要选 16G 的 U-Boot 包)。 - 3选择系统镜像版本
选 RevyOS,版本选 20251226(与 Support Matrix 当前 good 记录、本课验收样机一致)。向导会下载并校验对应镜像;下载目录以终端提示为准。 - 4进入烧录模式
板子断电。按住板上 BOOT 键不放,再插入连向主机的 USB-C;主机应能枚举到 fastboot 设备。保持按住直至fastboot devices能看到设备(向导也会提示时机)。 - 5写入并观察预期输出
按向导确认后开始写入。成功时终端会出现各分区 flash 完成、无 error 的提示;失败则根据报错检查线材、BOOT 时机与fastboot devices。写入完成后按提示松开 BOOT、重新上电。
# 主机:启动一键准备(交互菜单以本机 ruyi 为准) $ ruyi update $ ruyi device provision # 选择:Sipeed LicheePi 4A → 16G → RevyOS 20251226 # 进入烧录模式后,另开终端可自检(可选) $ sudo fastboot devices # 期望:出现一列设备序列号 + fastboot
u-boot-with-spl-lpi4a-16g.bin、boot-lpi4a-20251225_175338.ext4.zst、root-lpi4a-20251225_175338.ext4.zst,用 zstd -d 解压后,按 Support Matrix 中的 fastboot flash 顺序写入。细节以该 README 与 Sipeed 文档为准。
首次启动验证(验收样机实输出)
默认用户 / 密码多为 debian / debian(以镜像说明为准)。串口或 SSH 登录后执行:
$ cat /sys/firmware/devicetree/base/model; echo Sipeed Lichee Pi 4A 16G $ cat /etc/revyos-release BUILD_ID=20251225_175338 BUILD_DATE=20251225 BOARD_NAME=lpi4a RELEASE_ID=20251226 COMMIT_ID=65b79515309b7d77816def1e83f0d5a95178ab70 RUNNER_ID=20508594622 $ uname -m riscv64 $ hostname revyos-lpi4a $ free -h | head -2 total used free shared buff/cache available Mem: 15Gi ... $ ip -br addr # 期望:除 lo 外,有网口(如 wlan0 / end0)拿到局域网 IP
| 检查项 | 命令 | 期望(本课样机) |
|---|---|---|
| 板型 | cat /sys/firmware/devicetree/base/model | 含 Lichee Pi 4A 16G |
| RevyOS 发行标识 | cat /etc/revyos-release | RELEASE_ID=20251226、BOARD_NAME=lpi4a |
| 架构 | uname -m | riscv64 |
| 内存规格 | free -h | 总量约 15–16 Gi(16G 板) |
| 账户 | id | 常见为用户 debian |
| IP 地址 | ip -br addr | 有有效局域网 IP |
| 路由 | ip route | 有默认网关 |
| 时间 | timedatectl | 时间正确(错了会导致 TLS 失败) |
| 软件源 | sudo apt update | 更新成功 |
/etc/os-release 可能显示底层 Debian 代号(如 forky/sid),确认「是不是本课这套 RevyOS」请看 /etc/revyos-release,不要只看 PRETTY_NAME。
三条开发通道
串口(UART)
本地调试线
UART 是按位串行收发的接口。接线:GND-GND、TX→RX、RX→TX,3.3V。不依赖网络,直接看启动日志。
SSH
远程主通道
SSH 是加密的远程终端。日常开发用它登录板子。本课用 Ed25519 密钥登录;首次连接须核对主机指纹。
SCP
文件传输
SCP 复用 SSH 连接拷文件。上传后在板端跑 sha256sum,与电脑端哈希一致即传输完整。
| 通道 | 怎么连 | 要网络吗 | 加密吗 | 典型场景 |
|---|---|---|---|---|
| 串口 UART | 物理线直连板子排针 | 否 | 否 | 开机引导日志、SSH 连不上时救急 |
| SSH | 走网络连板子 IP | 是 | 是 | 日常登录敲命令 |
| SCP | 复用 SSH 连接 | 是 | 是 | 电脑与板子之间传文件 |
# 板端启用 SSH $ sudo systemctl enable --now ssh # 电脑生成密钥 $ ssh-keygen -t ed25519 -C "riscv-course" # 首次连接——核对指纹后再输入 yes $ ssh user@board-ip # 部署公钥并免密验证 $ ssh-copy-id user@board-ip $ ssh user@board-ip 'hostname; uname -m'
# SCP 上传并校验 $ printf 'transfer test\n' > test.txt $ sha256sum test.txt $ scp test.txt user@board-ip:/tmp/ $ ssh user@board-ip 'sha256sum /tmp/test.txt'
known_hosts 旧记录。
一键准备与一键编译
手工烧录与手工 SSH/SCP 之外,ruyi 提供两类自动化能力:
一键准备
按设备支持列表自动下载镜像并写入板子存储,适合设备明确受支持、写入目标介质正确的场景。
一键编译
封装交叉工具链调用与常见构建参数,适合快速验证工具链或标准化构建。
# 以本机 ruyi 帮助为准 $ ruyi device --help $ ruyi device provision --help
ruyi device provision(选 LicheePi 4A / 16G / RevyOS 20251226)。一键编译与手工 SCP/SSH 也要掌握。Support Matrix 与 Sipeed 文档用于对照与排障。
revyos-release)· 串口接线记录 · SSH 密钥登录 · SCP 双向哈希一致。
交叉编译、Makefile 与 CoreMark
为何必须交叉编译
开发电脑的 CPU 执行 x86_64(少数机器是 ARM)机器码;荔枝派 4A 执行 riscv64 机器码。两边指令编码不同。
在电脑上用本机 gcc main.c -o app,得到的是本机架构的 ELF,只能在本机跑。拷到板端,Linux 内核会拒绝加载,常见报错是 Exec format error。板端编好的 RISC-V 程序拷回电脑,同样跑不了。
为什么内核会拒绝?可执行文件开头有一段 ELF 头,其中的 e_machine 字段写明这份文件属于哪种架构。内核加载程序时检查这个字段:和当前 CPU 架构不一致就拒绝加载,报 Exec format error。file 读的正是同一个字段——所以 file 说它是 RISC-V,就预判了它在 x86 电脑上跑不了;说它是 x86-64,就预判了它在板子上跑不了。
在荔枝派上实测(本课真板):
# 把两种产物都拷到板子 /tmp 再运行 $ scp mini-riscv mini-host debian@板子IP:/tmp/ $ ssh debian@板子IP 'cd /tmp && ./mini-riscv; echo "exit=$?"' # exit=0 —— RISC-V 产物在板端正常跑 $ ssh debian@板子IP 'cd /tmp && ./mini-host; echo "exit=$?"' bash: line 1: ./mini-host: cannot execute binary file: Exec format error # exit=126 —— x86 产物被内核拒绝,报 Exec format error
交叉工具链仍在电脑上运行,但专门生成 RISC-V 机器码,并链接面向 RISC-V Linux 的 C 库。本课经 RuyiSDK 安装,前缀是 riscv64-ruyisdk-linux-gnu-。三元组 riscv64-ruyisdk-linux-gnu 标明:CPU 为 riscv64、系统为 Linux、用户态约定为 GNU。选成 unknown-elf 会得到裸机工具链,不适合本课跑 Linux 用户程序。
同一份源码,三条编译路径
同一份 main.c 可以走出三种产物。分清「编给谁、能在哪跑」:
抓住三点:① 编译器选错,架构就错;② 用 file 读 ELF 架构字段验收;③ 交叉编译只解决「编对架构」——把文件传到板端并运行,是传输与加载的另一步。
交叉工具链内部仍是编译 → 汇编 → 链接,目标一律是 RISC-V:产出 RISC-V 汇编与 .o,再链上 RISC-V 版 C 运行库(sysroot)。
板端若已安装 gcc,可在板子上直接编译就地运行(上图第三条路)。本课后续章节会用到;板端原生编译可作对照,但不能代替主机交叉产物。
亲眼看到指令差异:反汇编
「指令集不同」光听概念记不牢。把同一份 main.c 用两种编译器各编一份,再用 objdump -d 把机器码反回汇编,两边从助记符到编码完全不同:
# 交叉编译 → RISC-V 反汇编 $ riscv64-ruyisdk-linux-gnu-objdump -d mini-riscv | sed -n '/<main>:/,/^$/p' 0000000000000614 <main>: 614: 1141 addi sp,sp,-16 616: e406 sd ra,8(sp) 61c: 4781 li a5,0 61e: 853e mv a0,a5 # 本机编译 → x86-64 反汇编 $ objdump -d mini-host | sed -n '/<main>:/,/^$/p' 0000000000001129 <main>: 1129: f3 0f 1e fa endbr64 112d: 55 push %rbp 1131: b8 00 00 00 00 mov $0x0,%eax 1137: c3 ret
同样是「把 0 放进返回值」这一个动作,RISC-V 用 li a5, 0 加 mv a0, a5 两条指令,x86 用 mov $0x0, %eax 一条——助记符、寄存器、机器码编码全不一样。这就是为什么两边产物不能互换:内核检查 ELF 头时直接拒收。
Makefile 跟做:本机 vs 交叉
Makefile 描述如何编译工程;敲 make 按规则调用编译器。把交叉前缀写进 Makefile,避免每次手敲冗长命令。
# Makefile — 交叉编译模板 CROSS_COMPILE := riscv64-ruyisdk-linux-gnu- CC := $(CROSS_COMPILE)gcc CFLAGS := -O2 -Wall TARGET := app $(TARGET): main.c $(CC) $(CFLAGS) main.c -o $(TARGET) clean: rm -f $(TARGET) .PHONY: clean
用同一份源码对照两条路径(讲义跟做到 file 为止,不必 SCP):
$ printf 'int main(void) { return 0; }\n' > main.c $ gcc main.c -o app-host $ file app-host # … ELF … x86-64 …(本机架构) $ ./app-host # 本机可执行 $ make # 或:riscv64-ruyisdk-linux-gnu-gcc main.c -o app $ file app # … ELF … UCB RISC-V … $ ./app # 本机应失败(指令集不对)
CC / CROSS_COMPILE 会默默用本机 GCC,产物在板端报 Exec format error。先用 file 查架构。Makefile 配方行必须以 Tab 缩进。
构建 CoreMark(讲义收口:编出 + file)
CoreMark 是测处理器算力的小基准程序,输出可比较的分数。本章用它走通工具链:先在主机交叉编出 RISC-V 可执行文件,再传到板端并跑出分数。
# 在 x86 Linux 上:先激活虚拟环境,再进入课程仓库 $ . ~/venv-gnu-ruyisdk/bin/ruyi-activate $ cd chapters/ch01/code $ make $ file coremark/coremark.exe coremark/coremark.exe: ELF 64-bit LSB executable, UCB RISC-V, ...
源码已放在 chapters/ch01/code/coremark/(官方 CoreMark)。Makefile 在 x86 Linux 上自动选用交叉编译器;在荔枝派上则自动使用板载 gcc。
file 对照 · CoreMark 的 RISC-V 可执行文件(尚未上板)。