嵌入式 Linux 初学者指南 – 第 2 部分

大家好!我是大聪明-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-bootlinuxbuildroot的内容,您可能会对其中丰富的目录和文件感到惊讶。别担心,没有必要彻底分析组件结构(至少目前不需要),但了解关键的目录和文件非常重要。

3.2.1. U-Boot

  • arch --- 位于相应子目录(armx86等)中的"与架构相关的"代码。其内容如下:

    • dts --- 设备树硬件描述文件(*.dts*.dtsi
  • board --- 特定于主板的代码。目录由供应商命名(例如sunxinvidia等)。其中包含用于初始化、电源设置和其他操作的主板特定代码。

  • configs --- 典型的 U-Boot 配置(*_defconfig

  • doc --- 官方文档。

  • 驱动程序------各种外围设备(UART、SPI 等)的驱动程序

3.2.2. Linux

  • 文档--- 官方文档。

  • arch --- 位于相应子目录(armx86等)中的"与架构相关的"代码。其内容如下:

    • boot/dts --- 设备树硬件描述文件(*.dts*.dtsi

    • configs --- 典型的 Linux 配置(*_defconfig

  • 驱动程序--- 各种设备(网络、总线、图形、声音等)的驱动程序

3.2.3. 构建根目录

  • board --- 特定主板的脚本、补丁和设置

  • configs --- 典型的 Buildroot 配置(*_defconfig

  • docs --- 官方文档。

  • --- 可通过 Buildroot 构建的包

3.2.4. 外层

可以想象,任何直接对u-bootlinuxbuildroot进行的更改都会淹没在浩瀚的文件和目录中。将整个源代码拖入代码库并非最佳选择。

为了解决这个问题,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-bootlinux目录------它们已经不再需要了:

复制代码
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. 首次启动

启动开发板。如果所有配置和连接正确,您将在终端中看到以下内容:

  1. U-Boot启动流程

  2. 5 年后再见U -Boot...

  3. 内核启动过程

  4. 我们的Hello Buildroot 系统欢迎横幅在这里!

我建议您登录。用户名:root,无需密码。

最后要检查的是内核版本:

复制代码
`uname `-r

在内核版本旁边,您会看到**HelloLinux------**这意味着我们所有的设置都已正确应用。

要退出,minicom请按Ctrl+A、X

恭喜:您已经配置、构建并启动了自己的嵌入式 Linux 系统!

这条艰难的道路上,我们已经迈出了第一步。接下来还有更多。

结果

因此,我们使用 Docker 准备了一个工作环境,分析了 U-Boot、Linux、Buildroot 及其外层的结构,在我们的板上配置、构建和启动了嵌入式 Linux。

在你开始玩你的新"玩具"之前,请允许我先说几句关于下一章的内容。

简而言之,我们将深入探讨。我们将详细介绍 Buildroot和bashKConfig 基础知识。它是什么,它如何工作,为什么需要它,以及它带来了哪些机会。make

会有很多理论,但是没有它,嵌入式就不可能实现。

现在,我先不打扰你了。你可以自己动手试试:探索一下文件系统结构,尝试不同的命令,以及探索一下系统目录------例如**/proc**。

感谢您抽出时间。再见!

相关推荐
feng_blog66882 小时前
【信创系统】统信UOS Linux4.19+libbpf开发ebpf程序实现文件操作的实时监控
linux·ebpf
祎直向前4 小时前
在Ubuntu中安装并配置ssh
linux·ubuntu·ssh
南林yan5 小时前
Debian系统的多内核共存
linux·debian·linux内核
skywalk81635 小时前
尝试Auto-coder.chat使用星河社区AIStudio部署的几个大模型:文心4.5-21b、Deepseek r1 70b、llama 3.1 8b
linux·服务器·人工智能·大模型·aistudio
QiTinna6 小时前
系统运维Day02_数据同步服务
linux·同步·rsync
阿猿收手吧!6 小时前
【Linux网络】shutdown()与close()的区别
linux·网络
LCG元6 小时前
Linux 磁盘管理从入门到精通:LVM 扩容实战案例
linux
liu****6 小时前
12.线程(二)
linux·开发语言·c++·1024程序员节
咯哦哦哦哦7 小时前
vscode arm交叉编译 中 cmakeTools 编译器设置
linux·arm开发·vscode·编辑器