# \[第2课时 · 3/8\] Kernel 交叉编译流程

**URL:** <https://forum.t-firefly.com/t/topic/17508>\
**Category:** Course\
**Tags:** linux, 中山学院课程\
**Created:** [October 19, 2026, 7:56am UTC](https://forum.t-firefly.com/t/topic/17508 "2026-10-19T07:56:27Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![neutionwei](https://forum.t-firefly.com/user_avatar/forum.t-firefly.com/neutionwei/32/12127_2.png) [@neutionwei](https://forum.t-firefly.com/u/neutionwei)\
**Post date:** [October 19, 2026, 7:56am UTC](https://forum.t-firefly.com/t/topic/17508/1 "2026-10-19T07:56:27Z")

</div>

## 0. 这一节要解决什么

编译内核的机器是 x86\_64 的 PC（或虚拟机），运行内核的板子是 ARM64——CPU 指令集完全不同，PC 上的 gcc 编出的程序板子根本跑不了。本节回答： **怎样让 x86 主机产出 ARM64 的内核** ，以及 **手工 make 与 SDK 脚本两种方式的关系** 。

## 1. 三方关系

```auto
编译主机 (x86_64) ──调用──→ 交叉工具链 ──输出──→ 目标板 (ARM64)
运行 make / 脚本 aarch64-linux-gnu-gcc 加载并执行 Image
                       在主机上运行，产出 ARM64 指令

```

交叉编译不是「在 PC 上编译然后拷过去」那么简单—— **编译器本身决定生成哪种指令集** 。普通 gcc 生成 x86\_64 指令；交叉工具链前缀为 `aarch64-linux-gnu-` 的 gcc 生成 ARM64 指令。

## 2. 两个参数各管一件事

| 参数 | 作用 | 错误后果 |
| --- | --- | --- |
| `ARCH=arm64` | 选择目标架构：决定使用 `arch/arm64/` 下的代码与 defconfig | 找不到 defconfig，或编出 x86 内核 |
| `CROSS_COMPILE=aarch64-linux-gnu-` | 指定工具链前缀：make 会调用 `aarch64-linux-gnu-gcc` 等 | 报 `aarch64-linux-gnu-gcc: No such file`，或用了主机 gcc |

**记忆法** ：`ARCH` 管「用哪套架构的源码」，`CROSS_COMPILE` 管「用哪套编译器」。

## 3. 工具链从哪里来

两种来源：

1. **系统安装** ：`sudo apt install gcc-aarch64-linux-gnu`（版本可能偏旧）
2. **SDK 自带** ：在 `prebuilts/` 目录下，版本与 SDK 匹配

用 SDK 入口（`build.sh`）编译时，脚本会自动把工具链路径加入环境， **不需要手工设置** `CROSS_COMPILE`；这也是推荐用 SDK 入口的原因之一。

## 4. 两种方式

**手工方式** ——理解原理用，在 `kernel/` 目录内执行：

```bash
cd kernel
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- rockchip_linux_defconfig
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig # 可选
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc) Image dtbs

```

产物在 `arch/arm64/boot/Image` 与 `arch/arm64/boot/dts/rockchip/*.dtb`。

**SDK 方式** ——课程实际使用，在 SDK 根目录执行：

```bash
./build.sh lunch # 选择 firefly_rk3576_roc-rk3576-pc_ubuntu_defconfig
./build.sh extboot # 编译内核并生成 boot 分区镜像 kernel/extboot.img

```

`extboot` 目标会完成「配置内核 → 编译 → 打包 boot 分区镜像」一整段，产物在 `kernel/extboot.img` 与 `kernel/extboot/` 目录。

## 5. 增量编译与清理

- **增量** ：直接重跑 `./build.sh extboot`，Kbuild 只重编改动过的文件，第二次通常只需几十秒
- **清理内核** ：`./build.sh clean kernel`；全量清理 `./build.sh cleanall`
- **何时必须 clean** ：切换 defconfig / 工具链 / 板级配置之后，残留的 `.o` 与 `.config` 可能导致产物错乱——出现诡异错误时，先 clean 再编是标准动作
- **并行度** ：`-j$(nproc)` 用满所有核；内存小于 8G 时适当调小，避免 OOM

## 6. 常见报错对照

| 报错 | 原因 | 处理 |
| --- | --- | --- |
| `aarch64-linux-gnu-gcc: No such file or directory` | 工具链不在 PATH | 改用 SDK 入口，或给 `CROSS_COMPILE` 配绝对路径 |
| `arch/arm64/configs/xxx: No such file` | `ARCH` 未设或 defconfig 名不对 | 核对 `ARCH=arm64` 与配置文件名 |
| 编译到一半 `Killed` / `cc1: out of memory` | 并行度过高，内存耗尽 | 减小 `-j` 值 |
| 产物时间戳是旧的、改动没生效 | 增量编译未识别 / 残留状态 | `./build.sh clean kernel` 后重编 |

## 7. Lab：两种方式各跑一遍，记录证据

```bash
# 1) 手工编一个 dtb（快，适合验证工具链）
cd kernel
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- rockchip_linux_defconfig
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- rk3576-firefly-roc-rk3576-pc.dtb
ls -l arch/arm64/boot/dts/rockchip/rk3576-firefly-roc-rk3576-pc.dtb

# 2) SDK 全流程
cd <SDK>
./build.sh lunch # 选 firefly_rk3576_roc-rk3576-pc_ubuntu_defconfig
time ./build.sh extboot # 记录耗时
ls -l kernel/extboot.img kernel/extboot/

```

**要交的证据** ：两条产物的 `ls -l` 输出（含时间戳）与 `time` 耗时。

## 8. 本节小结

- 交叉编译的三方：x86 主机跑工具，`aarch64-` 工具链产 ARM64 指令，板子只负责运行
- `ARCH` 选架构源码，`CROSS_COMPILE` 选编译器；SDK 入口会自动备好两者
- 手工 make 用于理解原理；课程与实际开发用 `./build.sh extboot`
- 增量编译快；切配置后先 clean；报错先对表

## 9. 本节思考

**Q1：为什么不能直接在板子上编译内核？**

> **查看答案**
>
> 技术上可行（板子上有 gcc 就能自编译），但实际不可取：内核全量编译需要数 GB 内存与大量 CPU 时间，RK3576 的算力与内存远不如 x86 主机，编译一次可能要数小时甚至 OOM。交叉编译把「重计算」放在主机、「轻运行」放在板子，是嵌入式开发的标准分工。

**Q2：手工 make 时漏掉 `ARCH=arm64`，会发生什么？为什么？**

> **查看答案**
>
> make 按主机架构（x86\_64）处理：会去 `arch/x86/` 找 defconfig（报 No such file），即使运气好编下去，生成的也是 x86\_64 内核，板子无法执行。因为内核构建系统用 `ARCH` 决定架构目录、头文件与指令集相关的全部选择，默认值就是当前主机架构。

**Q3：`./build.sh extboot` 比「手工 make Image dtbs」多做的是什么？**

> **查看答案**
>
> 多了「准备板级配置 + 打包」两段：按板级入口设置 defconfig 与配置片段生成 `.config`、选定 `RK_KERNEL_DTS_NAME` 指定的 DTS，并把 Image、DTB 与 extlinux 配置打包成 boot 分区镜像 `kernel/extboot.img`。 **SDK 脚本是便捷入口，不是另一套编译系统** ——底层仍是 Kbuild 在干活。
