大家好!我是大聪明-PLUS!
在第一篇文章中,我们介绍了基础知识:嵌入式 Linux 是什么、它与常规发行版有何不同、它由什么组成、如何启动以及可以使用哪些工具来构建它。
我希望对这个主题感兴趣的人已经拥有一块带有 SoC 的电路板------没有它,一些步骤将会被遗漏,并且结果的享受将是不完整的。
现在是时候从理论转向实践了!
目录
3.了解Buildroot
3.1 准备
Buildroot 是一个多组件系统,需要工作环境才能运行。此外,最终的构建也需要在某个地方运行。所以,我们首先准备好所需的一切。
3.1.1. 必要设备
设备清单相当简单:
-
带有 SoC 的单板计算机
-
MicroSD 卡
-
USB-MicroSD 适配器
-
USB-UART适配器
-
用于连接适配器和单板计算机的电线
由于我们才刚刚开始使用这项技术,最好准备一块支持 Buildroot 的开发板。我使用的是 Sunxi 的 OrangePi PC,它基于 ARM 架构的 Allwinner H3 SoC。
3.1.2. 工作环境
您几乎可以在任何地方构建 EL,但我建议使用在 ext4 文件系统上部署了 Buildroot 环境的 Linux PC。就我而言,是 Ubuntu 22.04 LTS。
为了避免使主系统混乱,我们将在 Docker 容器中构建嵌入式 Linux。
在工作过程中,我们将通过 UART 与单板计算机通信,因此我们需要在操作系统上安装一个合适的实用程序。我的程序是minicom:
sudo` apt install `-y` minicom; \
`sudo` usermod `-aG` dialout `$USER`; \
newgrp dialout`
还建议立即将所有内容安排为存储库,因此您需要安装git:
sudo` apt install `-y` `git
现在让我们创建一个工作目录、必要的子目录,将其全部包装在git一个存储库中并下载Buildroot:
mkdir` `-p` `"$HOME"`/buildroot-builder/{docker,output}; \
`cd` `"$HOME"`/buildroot-builder; \
`git` init `-b` master; \
`git` submodule add `--depth=1` https://github.com/buildroot/buildroot.git buildroot; \
`git` `-C` buildroot fetch `--depth=1` origin tag `2025`.05; \
`git` `-C` buildroot checkout `2025`.05; \
`cat` > .gitignore `<< 'EOF'`
`/output`
`/buildroot/*`
`*.old`
`EOF`
`git` add buildroot docker .gitignore .gitmodules`
Buildroot 的最新版本将于 2025 年 7 月发布。
为了进一步熟悉组件的结构及其配置,我们还将从Linux下载U-Boot:
git` clone `--depth=1` `-b` v2025.07 https://github.com/u-boot/u-boot.git u-boot; \
`git` clone `--depth=1` `-b` v6.15 https://github.com/torvalds/linux.git linux`
所使用的版本是截至 2025 年 7 月的 Linux 和 U-Boot 的最新稳定版本。
让我们创建一个 Docker 镜像。在我的例子中,它基于Debian 11镜像:
cat` > docker/Dockerfile `<< 'EOF'`
`FROM debian:11`
`ARG UID=1000`
`ARG GID=1000`
`ARG USERNAME=builder`
`RUN apt update && \`
` apt install -y sudo git && \`
` groupadd -g ${GID} ${USERNAME} && \`
` useradd -m -u ${UID} -g ${GID} -s /bin/bash ${USERNAME} && \`
` echo "${USERNAME} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers`
`USER ${USERNAME}`
`WORKDIR /host`
`EOF`
docker build `--build-arg` `UID=$(id -u)` `--build-arg` `GID=$(id -g)` `--tag` buildroot-builder-image `-f` docker/Dockerfile docker`
让我们启动容器:
`docker run `--name` buildroot-builder `-v` /home/`$USER`/buildroot-builder:/host `-it` buildroot-builder-image /bin/bash`
对于图形爱好者
让我们在容器中安装几个基本实用程序:
sudo` apt update && `sudo` apt install `-y` mc nano`
-
mc--- 方便浏览目录 -
nano--- 用于编辑文本文件(Vim 爱好者请原谅我)
由于我们将首先练习独立于 Buildroot 设置 U-Boot 和 Linux,因此需要手动安装它们的一些依赖项:
sudo` apt install `-y` flex bison`
安装最少的软件包集:
sudo` apt install `-y` build-essential libncurses-dev debianutils pkg-config \
diffutils findutils binutils patch bzip2 unzip rsync `make` `bash` \
gzip perl cpio file `gawk` `wget` `sed` `gcc` g`++` tar bc`
安装可选包:
sudo` apt install `-y` openssh-client default-jdk python3-pip subversion \
mercurial graphviz python3 dblatex `curl` cvs `git` w3m; \
pip install matplotlib asciidoc argparse aiohttp bazaar`
对于那些已将图形放入容器并计划使用make gconfig或的用户make xconfig,需要交付以下包:
sudo` apt install `-y` qtbase5-dev-tools libqt5widgets5 libglib2.0-dev \
libgtk2.0-dev libglade2-dev qtbase5-dev libqt5gui5 qt5-qmake`
我们还将设置BR2_EXTERNAL 环境变量,让 Buildroot 了解外部层。稍后我们将讨论修改 Buildroot 的机制,但现在,让我们简单地在external目录中创建一个最小的外部层结构:
echo` `"export BR2_EXTERNAL=/host/external"` >> ~/.bashrc; \
`source` ~/.bashrc; \
`mkdir` `-p` `"$BR2_EXTERNAL"`/{board/test,configs}; \
`cd` `"$BR2_EXTERNAL"`; \
`touch` external.mk; \
`cat` > external.desc `<< 'EOF'`
`name: TEST_EXTERNAL_LAYER`
`desc: Test external layer for Buildroot practice`
`EOF`
`cat` > Config.in `<< 'EOF'`
`menu "Test external layer options"`
`endmenu`
`EOF
至此,工作环境的搭建就完成了。在开始构建之前,我们先来看看下载的项目内容。
3.2. 组件结构
如果您已经查看过u-boot 、linux 或buildroot的内容,您可能会对其中丰富的目录和文件感到惊讶。别担心,没有必要彻底分析组件结构(至少目前不需要),但了解关键的目录和文件非常重要。
3.2.1. U-Boot
-
arch --- 位于相应子目录(arm 、x86等)中的"与架构相关的"代码。其内容如下:
- dts --- 设备树硬件描述文件(*.dts 、*.dtsi)
-
board --- 特定于主板的代码。目录由供应商命名(例如sunxi 、nvidia等)。其中包含用于初始化、电源设置和其他操作的主板特定代码。
-
configs --- 典型的 U-Boot 配置(*_defconfig)
-
doc --- 官方文档。
-
驱动程序------各种外围设备(UART、SPI 等)的驱动程序
3.2.2. Linux
-
文档--- 官方文档。
-
arch --- 位于相应子目录(arm 、x86等)中的"与架构相关的"代码。其内容如下:
-
boot/dts --- 设备树硬件描述文件(*.dts 、*.dtsi)
-
configs --- 典型的 Linux 配置(*_defconfig)
-
-
驱动程序--- 各种设备(网络、总线、图形、声音等)的驱动程序
3.2.3. 构建根目录
-
board --- 特定主板的脚本、补丁和设置
-
configs --- 典型的 Buildroot 配置(*_defconfig)
-
docs --- 官方文档。
-
包--- 可通过 Buildroot 构建的包
3.2.4. 外层
可以想象,任何直接对u-boot 、linux 或buildroot进行的更改都会淹没在浩瀚的文件和目录中。将整个源代码拖入代码库并非最佳选择。
为了解决这个问题,Buildroot 有一个解决方案------外部树 ,或外部层。
实际上,外层只是一个目录,其中包含其配置、附加包、补丁、驱动程序、设备树文件等。对外层的结构没有特定要求,但官方文档建议遵循这种方法。
在准备工作环境时,我们创建了它的最小结构。目前缺少 U-Boot、Linux 和 Buildroot 的配置文件。让我们看看这些文件是什么以及如何创建它们。
3.3. 配置组件
每个组件,无论是 Buildroot、Linux 还是 U-Boot,都可以使用变量进行配置make。这些变量存储在文件中,文件可以分为几种类型:
-
默认设置分布在各个组件文件中。
-
当前设置 存储在**.config文件中。**
-
*_defconfig 文件- 非默认设置
创建最后两个有一组规则make:
-
make board_defconfig---从指定的***_defconfig** 创建**.config文件** -
make savedefconfig---从**.config** 创建***_defconfig文件**
如果您不熟悉
make,请不要担心。我们稍后会详细介绍它的结构。现在,只需记住:make您需要从相应组件的根目录调用它。
有各种用于更改组件的**.config**文件的交互式菜单:
-
make menuconfig--- 基于curses的文本界面。 -
make nconfig--- 基于ncurses的文本界面。 -
make gconfig--- 基于GTK+ 的图形界面。 -
make xconfig--- 基于Qt的图形界面。
我将使用menuconfig作为最通用且易于使用的选项。
让我们尝试为组件创建一个**.config文件并使用** menuconfig更改其配置。
3.3.1 了解 MenuConfig
我建议从u-boot开始。正如我之前提到的,我的主板是 Sunxi 的 OrangePi PC,板载一个 ARM SoC。
进入u-boot 并创建一个**.config**文件:
cd` /host/u-boot; \
`make` orangepi_pc_defconfig`
现在您可以调出配置菜单:
make` menuconfig`
一个包含各种设置组的界面出现在我们面前。操作非常简单:
-
向上和向下箭头 - 在项目之间移动。
-
左右箭头或Tab - 在菜单和下面的按钮之间切换(选择 、退出 、帮助等)。
-
输入--- 选择一项或确认一项操作。
-
双击Esc返回上一级或退出菜单。
-
此菜单对于所有组件都是相同的,因此您可以进行实验:浏览菜单,更改一些设置,查看主菜单和子菜单之一中的帮助,尝试使用搜索功能,将结果保存在 /host/u-boot/.config中,再次打开菜单并确保设置确实已更改。
完成了吗?这里有一个快速挑战来巩固一下:在 Linux 中启用对Realtek RTL8152/RTL8153 USB 网络驱动程序的 内置支持。Linux 有一个特殊功能:make调用它时需要指定体系结构:
cd` /host/linux; \
`make` `ARCH=`arm sunxi_defconfig; \
`make` `ARCH=`arm menuconfig`
任务完成了吗?如果完成了,你可以放心地删除u-boot 和linux目录------它们已经不再需要了:
cd` /host; \
`rm` `-rf` linux u-boot`
接下来,我们删除它们的依赖关系:
sudo` apt remove `-y` flex bison && `sudo` apt autoremove `-y
稍后如何配置 Linux 和 U-Boot?当然是使用 Buildroot。
3.3.2. 通过 Buildroot 配置
我们进入buildroot ,在外层创建我们需要的***_defconfig文件的副本,之后我们创建一个** .config文件:
cd` /host/buildroot; \
`cp` configs/orangepi_pc_defconfig ../external/configs/test_defconfig; \
`make` `O=`../output test_defconfig`
此参数
O=指定 Buildroot 构建的输出目录。
现在我们可以访问make配置组件的规则:
-
make linux-menuconfig--- 调用 Linux 配置菜单 -
make uboot-menuconfig--- 调用 U-Boot 配置菜单
确保 Buildroot 配置中包含相应的组件。否则,命令将失败。
第一次调用这些规则时,您必须等待组件加载并配置其工作环境。
在组装之前,我建议更改每个组件中的一个参数:
-
u-boot
make O=../output uboot-menuconfig-
启动选项
-
自动启动选项
-
(5)自动启动前的延迟秒数
-
\*\] 通过特定的输入键/字符串停止自动启动
-
\*\] 启用 Ctrl-C 自动启动中断
-
-
-
-
Linux
make O=../output linux-menuconfig-
常规设置
- (HelloLinux)本地版本 - 附加到内核版本
将配置保存到文件
/host/external/board/test/linux.config -
-
构建根
make O=../output menuconfig-
系统配置
- (你好 Buildroot!)系统横幅
-
核心
-
内核配置(使用自定义(def)配置文件)
-
($(BR2_EXTERNAL)/board/test/linux.config) 配置文件路径
-
-
引导加载程序
-
U-Boot
-
U-Boot 配置(使用自定义 (def)config 文件)
-
($(BR2_EXTERNAL)/board/test/u-boot.config) 配置文件路径
-
-
将配置保存到文件
/host/output/.config -
组件已配置完毕------现在您可以更新外层的 Buildroot 的***_defconfig文件:**
make` `O=`../output savedefconfig`
设置已完成。让我们进入下一步:组装。
4. 第一步
4.1. 从 make 到 image
我想您make uboot-menuconfig已经make linux-menuconfig欣赏 Buildroot 的方法:您所需的一切都会自动下载、配置、编译和安装。
要组装所有组件,你只需要一个命令,以及一点耐心。这个命令已经很熟悉了make。
4.1.1. 系统组装
那么,让我们开始构建系统:
cd` /host/buildroot; \
`make` `O=`../output`
如果您遵循了选择电路板和配置组件的建议,则无需担心:一切都应该顺利组装。
当然,事情并不总是一帆风顺。有时,由于软件包版本不稳定、配置问题或第三方工具的意外行为,可能会出现构建错误。Buildroot 提供了一些用于解决此类问题的工具------我们稍后会介绍。
至于构建时间,它取决于许多因素:网络连接速度、RAM、处理器频率、磁盘速度以及核心数量。首次构建尤其耗时,因为 Buildroot 需要从头开始下载并编译所有软件包。
构建成功了吗?如果是这样,我建议对我们的代码库进行第一次提交:
cd` `"$HOME"`/buildroot-builder; \
`git` add external; \
`git` commit `-m` `"First step"`; \
`git` tag FirstStep`
现在让我们看一下输出目录的内容。
4.1.2. 输出目录结构
其中可以找到几个关键目录:
-
build --- 下载所有软件包的源代码和中间构建文件
-
主机是主机系统在构建过程中所需程序的隔离环境。它包含工具链、实用程序、库和头文件。
-
target --- 目标系统的根文件系统。此目录中的所有内容都可以在目标设备上访问。
-
图像--- 包含构建工件的目录
最令我们感兴趣的是图像。
4.1.3. 组装工件
工件列表取决于组件配置,但对于具有基本设置的 OrangePi PC 来说,它看起来像这样:
-
genimage.cfg --- 用于构建sdcard.img的配置文件
-
rootfs.* --- 根文件系统
-
sdcard.img - 用于在 SD 卡上录制的图像
-
sun8i-h3-orangepi-pc.dtb --- 编译的设备树
-
u-boot-sunxi-with-spl.bin --- 带有 SPL 的 U-Boot 可执行文件
-
u-boot.bin --- U-Boot 可执行文件
-
zImage是一个压缩的 Linux 内核。
我们稍后会详细讨论每个文件的功能。目前,我们只关注sdcard.img 文件。
4.2. 准备发布
启动前只剩下两个步骤:将图像写入 SD 卡并将开发板连接到 PC。
4.2.1. 录制到 SD 卡
通常,将图像写入 SD 卡的命令位于buildroot/board/<board> 的readme.txt文件中。
对于 OrangePi PC,这是文件buildroot/board/orangepi/orangepi-pc/readme.txt。其中的命令如下:
sudo` dd `if=`output/images/sdcard.img `of=`/dev/sdX`
让我们使用 MicroSD 转 USB 适配器将 SD 卡连接到电脑,然后在主操作系统中打开另一个终端。打开它lsblk并在列表中找到您的 SD 卡。在我的例子中,它是**/dev/sdb**。
确保你找到的驱动器是SD卡!否则,你可能会损坏另一个驱动器上的数据!
生成的命令是:
sudo` umount /dev/sdb*; \
`sudo` dd `of=`/dev/sdb `if="$HOME"`/buildroot-builder/output/images/sdcard.img `bs=`1M `status=`progress; \
`sudo` sync`
bs --- 一次写入的数据量。
status=progess --- 录制过程的输出
您可以将 SD 卡与 PC 断开并将其连接到开发板。
4.2.2. 将开发板连接到 PC
您不能直接连接到开发板上的任意 UART,您需要找到正确的 UART。通常,它会通过开发板上的一组单独引脚进行路由:RX、TX 和 GND。在 OrangePi PC 上,它们位于 HDMI 和电源连接器之间。
通常,UART 以 115200 波特、8 个数据位、1 个停止位、无奇偶校验协议和无流量控制运行。
所有这些 UART 参数和引脚都可以在*.dts 和***.dtsi**文件中找到。设备树是一个复杂的主题,因此我们稍后会更详细地介绍它。
将开发板连接到 UART-USB 适配器:开发板的 RX 连接到适配器的 TX,反之亦然。将 GND 1 连接到 1。
在您的电脑上运行以下命令:
`watch `-n` `1` `-t` `ls` /dev/ttyUSB* /dev/ttyACM*`
将适配器连接到电脑。运行的命令将显示适配器的路径。在我的例子中,它是**/dev/ttyUSB0**。
要终止命令,
watch请按Ctrl+C
我们之前已经安装好了它minicom。我们通过传递找到的设备的路径和 UART 速度来调用它:
`minicom `-D` /dev/ttyUSB0 `-b` `115200
现在我们需要配置我们的端口:
-
按Ctrl+A、O
-
转到串行端口设置选项卡
-
通过按下键盘上相应的字母来配置端口。设置如下:
-
E - Bps/Par/Bits:115200 8N1
-
F - 硬件流控制:否
-
G - 软件流控制:否
-
-
**选择将设置保存为 dlf,**将设置保存为默认配置
-
**选择"退出"**关闭配置菜单
一切准备就绪,可以启动主板了。
4.3. 首次启动
启动开发板。如果所有配置和连接正确,您将在终端中看到以下内容:
-
U-Boot启动流程
-
5 年后再见U -Boot...
-
内核启动过程
-
我们的Hello Buildroot 系统欢迎横幅在这里!
我建议您登录。用户名:root,无需密码。
最后要检查的是内核版本:
`uname `-r
在内核版本旁边,您会看到**HelloLinux------**这意味着我们所有的设置都已正确应用。
要退出,
minicom请按Ctrl+A、X。
恭喜:您已经配置、构建并启动了自己的嵌入式 Linux 系统!
这条艰难的道路上,我们已经迈出了第一步。接下来还有更多。
结果
因此,我们使用 Docker 准备了一个工作环境,分析了 U-Boot、Linux、Buildroot 及其外层的结构,在我们的板上配置、构建和启动了嵌入式 Linux。
在你开始玩你的新"玩具"之前,请允许我先说几句关于下一章的内容。
简而言之,我们将深入探讨。我们将详细介绍 Buildroot和bashKConfig的 基础知识。它是什么,它如何工作,为什么需要它,以及它带来了哪些机会。make
会有很多理论,但是没有它,嵌入式就不可能实现。
现在,我先不打扰你了。你可以自己动手试试:探索一下文件系统结构,尝试不同的命令,以及探索一下系统目录------例如**/proc**。
感谢您抽出时间。再见!