ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

使用Buildroot与QEMU快速构建嵌入式Linux仿真环境

使用Buildroot与QEMU快速构建嵌入式Linux仿真环境 1. 项目缘起为什么要在本地折腾Buildroot和QEMU如果你和我一样是个对嵌入式Linux或者系统底层有好奇心的开发者那你肯定遇到过这样的场景想研究一个新内核特性或者测试一个驱动又或者只是想验证一下某个开源软件在特定架构下的行为。这时候你首先想到的可能是找一块开发板。但现实往往是手头没有合适的硬件或者硬件到了环境搭建、交叉编译、烧录、调试……一套流程下来半天时间就没了效率极低。更别提那些需要频繁修改、快速迭代的场景了。这就是为什么我们需要一个轻量、快速、可重复的仿真环境。Buildroot QEMU这套组合拳完美地解决了这个问题。它让你能在自己的笔记本电脑上用几分钟时间从零开始构建一个完整的、可启动的Linux系统并在一个虚拟的硬件环境中运行它。整个过程完全自动化无需物理硬件极大地降低了学习和开发的门槛。简单来说Buildroot是一个高度自动化的构建系统它像一位全能的厨师你只需要提供一份“菜单”配置文件它就能帮你自动下载、配置、编译、打包出包含内核、根文件系统、引导程序等在内的完整Linux系统镜像。而QEMU则是一个功能强大的开源机器模拟器和虚拟器它扮演着“餐厅”的角色为Buildroot制作出的“套餐”提供一个虚拟的硬件平台比如ARM、MIPS、RISC-V等让你能立刻“品尝”到成果。这套方案的魅力在于其极致的简洁性和可控性。相比于庞大的发行版或复杂的Yocto项目Buildroot的配置直观生成的系统精简非常适合用来理解Linux系统从源码到启动的完整链条也是进行嵌入式原型开发、驱动调试、教学演示的利器。接下来我就带你走一遍完整的流程分享其中每一步的关键细节和我踩过的坑。2. 环境准备搭建你的“数字厨房”在开始烹饪之前我们得先把厨房收拾利索。整个过程在Linux主机上进行最为顺畅Windows和macOS用户可以通过WSL2或虚拟机获得类似的体验。这里我以Ubuntu 22.04 LTS为例。2.1 安装必要的构建工具和依赖Buildroot在编译过程中需要主机提供一系列的基础工具链和开发库。如果缺失编译会在中途报错非常影响体验。所以第一步我们把可能用到的依赖都装上。打开终端执行以下命令sudo apt update sudo apt install -y build-essential git wget cpio unzip rsync bc \ libncurses-dev libssl-dev python3 python3-pip bison flex \ libelf-dev dosfstools mtools parted这里解释几个关键包的作用build-essential: 包含gcc, g, make等核心编译工具。libncurses-dev: 提供make menuconfig图形化配置界面所需的库。bc: 内核编译过程中可能需要用到的一个计算器工具。bison flex: 语法分析器生成器某些软件包如uboot的编译会用到。libelf-dev: 处理ELF格式文件所需的库。dosfstools mtools parted: 用于创建和操作磁盘镜像文件如ext4,vfat。注意不同的Linux发行版包管理命令可能不同如Fedora用dnfArch用pacman。请根据你的系统调整。确保所有包成功安装避免后续编译因依赖缺失而中断。2.2 获取Buildroot和QEMU源码我们不需要单独安装QEMU因为Buildroot在构建时可以选择为我们编译一个针对特定架构优化的QEMU版本这样兼容性最好。当然系统里有一个基础版本的QEMU也无妨。首先获取最新稳定版的Buildroot源码。我习惯使用长期支持LTS版本相对更稳定。# 切换到你的工作目录例如 ~/workspace cd ~/workspace # 克隆Buildroot仓库如果网络慢可以考虑使用国内镜像源 git clone https://git.buildroot.net/buildroot cd buildroot # 切换到最新的LTS分支例如2024.02 git checkout 2024.02至此你的“数字厨房”——Buildroot就已经准备就绪了。它的目录结构非常清晰board/: 存放特定开发板的配置和补丁。configs/: 预置的配置文件*_defconfig。dl/: 下载的软件包缓存目录。output/: 构建输出目录编译完成后才会生成。package/: 所有可供选择的软件包定义。target/: 目标系统根文件系统的骨架和配置。3. 核心配置定制你的“系统菜单”Buildroot的强大之处在于其高度可配置性。我们通过make menuconfig来定制我们的系统。这个过程就像在餐厅点餐选择主架构、内核版本、要安装的软件包等等。3.1 选择基础配置模板Buildroot提供了大量针对不同硬件包括QEMU虚拟硬件的预设配置这为我们提供了一个完美的起点。# 在buildroot根目录下执行 make qemu_aarch64_virt_defconfig这条命令加载了针对QEMU ARM64虚拟平台virt机器的默认配置。它会设置好目标架构AArch64、工具链、内核版本等基础选项。执行后会在当前目录生成一个隐藏的.config文件。为什么选择qemu_aarch64_virt因为ARM64是目前最流行的嵌入式架构之一virt是QEMU提供的一个通用的、无对应真实硬件的虚拟平台它模拟了CPU、内存、PL011串口、virtio磁盘和网络设备等非常适合用来做通用性的学习和测试。3.2 深入定制系统细节加载默认配置后我们进入图形化配置界面进行微调。make menuconfig你会看到一个基于ncurses的蓝色配置界面。使用方向键导航回车键进入子菜单或选择选项空格键勾选/取消勾选[*]表示编译进系统[M]表示编译为模块[ ]表示不选Esc键返回上级。下面是我通常会调整的几个关键区域Target optionsTarget Architecture (AArch64 (little endian)) 确认架构是否正确。我们之前选的defconfig已经设好。Target Architecture Variant (cortex-A53) 可以选择一个具体的CPU型号QEMU的virt机器支持多种型号选一个常见的即可对仿真没影响。Toolchain这是重中之重。Buildroot可以使用外部工具链如Linaro GCC也可以自己构建一个工具链。对于入门和保证环境纯净我强烈推荐后者。Toolchain type (Buildroot toolchain) 选择让Buildroot自己构建。Kernel Headers (Latest stable version) 选择与你将要编译的内核版本匹配或更新的头文件版本。选“Latest”通常比较安全。C library (glibc) glibc功能最全兼容性最好。如果你的系统需要极致的精简 10MB可以考虑musl或uClibc-ng。这里我们选glibc。Enable C support 如果你后续可能需要编译或运行C程序就勾选上。System configurationSystem hostname 给你的虚拟机器起个名字比如qemu-virt。System banner 登录时显示的欢迎信息。Root password务必设置一个默认是空的这会导致无法通过串口登录。我通常设为root方便测试生产环境请用强密码。/dev management (Dynamic using devtmpfs eudev) 保持默认让系统动态管理设备节点。KernelKernel version (Latest stable version) 选择最新的稳定版内核。你也可以指定一个精确版本。Kernel configuration (Using a defconfig) 使用默认配置。Additional kernel configuration options 可以在这里添加内核参数。例如为了在QEMU中启用网络我们可以添加CONFIG_VIRTIO_NETy。不过virt平台的defconfig通常已经包含了。Target packages这是最有趣的部分你可以在这里勾选需要安装到根文件系统里的软件包。对于初次尝试我建议保持精简只选必要的BusyBox 已经默认选中它提供了基础的Linux命令ls,cp,ping等。Networking applications 展开勾选openssh。这样构建出的系统就可以通过SSH登录了比用串口方便很多。Text editors and viewers 可以勾选vim或nano方便编辑文件。Filesystem images 确认ext2/3/4 root filesystem被选中这是我们将要生成的根文件系统镜像格式。Filesystem imagesexact image(s) to build (ext4) 选择ext4格式。它是Linux上最常用的日志文件系统在QEMU中性能也不错。compression method (gzip) 选择压缩方式可以减小镜像体积。配置完成后一路按Esc退出并选择Yes保存配置到.config文件。实操心得make savedefconfig命令非常有用。它会把当前繁多的.config精简成只包含与默认配置不同之处的defconfig文件。你可以把这个文件保存下来比如cp defconfig configs/my_qemu_config以后就可以直接用make my_qemu_config_defconfig快速恢复这个配置了。4. 构建过程启动“自动烹饪”配置保存好后就可以开始构建了。这个过程是全自动的但耗时较长取决于你的电脑CPU和网络速度首次构建可能需要30分钟到1小时。# 在buildroot根目录下执行make。可以用 -jN 参数指定并行编译任务数N通常是你的CPU核心数1以加快速度。 make -j$(nproc)去泡杯咖啡耐心等待。Buildroot会依次执行以下步骤下载 根据配置下载Linux内核、BusyBox、工具链源码、以及你选择的所有软件包到dl/目录。网络是此阶段最大的变量如果某个包下载失败可以手动检查dl/目录下的对应文件是否完整或尝试使用代理。构建工具链 编译构建目标系统所需的交叉编译器gcc, binutils等。编译目标包 用上一步生成的交叉编译器依次编译Linux内核、BusyBox以及你选择的所有软件包。生成根文件系统 将编译好的所有二进制文件、库和配置文件按照target/目录下的骨架组装成一个完整的根文件系统。生成镜像 将根文件系统打包成我们指定的格式如ext4最终在output/images/目录下生成可用的镜像文件。构建成功后你会在output/images/目录下看到这些关键文件Image 压缩后的Linux内核镜像。rootfs.ext4 包含根文件系统的ext4格式磁盘镜像。qemu-aarch64-virt.dtb 设备树二进制文件Device Tree Blob用于描述virt平台的硬件信息给内核。可能还有start-qemu.sh等辅助脚本。5. 在QEMU中运行启动你的“虚拟餐厅”现在“套餐”已经做好是时候在QEMU这个“餐厅”里运行它了。Buildroot贴心地为我们生成了运行脚本。# 还是在buildroot根目录下 ./output/images/start-qemu.sh或者你也可以手动拼接QEMU命令这样更灵活qemu-system-aarch64 \ -M virt \ -cpu cortex-a53 \ -smp 4 \ -m 1024M \ -kernel output/images/Image \ -dtb output/images/qemu-aarch64-virt.dtb \ -append root/dev/vda consolettyAMA0 \ -drive fileoutput/images/rootfs.ext4,formatraw,ifvirtio \ -netdev user,ideth0 \ -device virtio-net-device,netdeveth0 \ -nographic逐行解释一下这个命令-M virt: 指定机器类型为QEMU的virt虚拟平台。-cpu cortex-a53: 指定CPU模型。-smp 4: 模拟4个CPU核心。-m 1024M: 分配1GB内存给虚拟机。-kernel/-dtb: 指定内核镜像和设备树文件。-append: 传递给内核的命令行参数。root/dev/vda告诉内核根文件系统在第一个virtio-blk设备上consolettyAMA0指定串口为控制台这样我们才能在终端看到输出。-drive: 指定磁盘镜像文件。ifvirtio使用virtio-blk设备性能优于模拟的IDE。-netdev user,ideth0/-device virtio-net-device,netdeveth0: 配置一个用户模式的网络后端和一个virtio-net网卡。用户模式网络允许虚拟机访问外部网络NAT方式但外部无法直接访问虚拟机。-nographic: 这个参数至关重要它告诉QEMU不使用图形界面并将串口输出重定向到当前控制台。这样我们就能在一个终端里完成所有操作。执行命令后你会看到内核启动日志飞速滚动最后出现登录提示Welcome to Buildroot buildroot login:输入用户名root和你之前设置的密码如果没设就是空密码直接回车就成功登录了你现在拥有一个完整的、运行在QEMU模拟的ARM64机器上的Linux系统。可以运行uname -als /ifconfig等命令验证。要退出QEMU先按CtrlA然后松开再按X键。6. 进阶配置与深度玩法一个能启动的系统只是开始。要让这个环境真正有用还需要一些进阶配置。6.1 启用网络与SSH登录我们之前已经勾选了openssh但要让SSH服务开机自启还需要一点配置。在Buildroot的menuconfig中进入System configuration-Init system (BusyBox init)。BusyBox的init足够简单。进入Target packages-Networking applications-openssh确保它被选中。关键步骤 在Target packages-Networking applications-openssh的子菜单里勾选install server configs和enable ssh server。重新构建 (make) 后新的根文件系统就会包含SSH服务端配置并默认启用。启动QEMU时确保使用了前面提到的网络参数 (-netdev user)。在虚拟机内运行ifconfig查看IP地址通常是10.0.2.15。然后你就可以从主机的另一个终端通过SSH连接了ssh root10.0.2.15踩坑记录用户模式网络 (-netdev user) 下虚拟机的IP是固定的10.0.2.15但主机无法直接ping通这个IP。这种模式只允许虚拟机主动访问外部网络。如果你需要主机和虚拟机互访或者虚拟机需要对外提供服务如Web服务器应该使用TAP网络或端口转发。例如在QEMU命令中添加-netdev user,hostfwdtcp::2222-:22这样将主机的2222端口转发到虚拟机的22端口就可以用ssh -p 2222 rootlocalhost连接了。6.2 添加自定义软件或文件有时你需要一个Buildroot官方仓库里没有的软件或者需要预置一些配置文件。有两种主要方法方法一使用 overlay覆盖层这是最常用、最干净的方法。Overlay是一个目录树其文件结构会直接覆盖到构建好的根文件系统上。在Buildroot目录外比如~/my_overlay创建一个目录并按照目标根文件系统的结构放置文件。例如创建一个启动脚本mkdir -p ~/my_overlay/etc/init.d echo -e ‘#!/bin/sh\n# My custom startup script\necho “Hello from overlay!”’ ~/my_overlay/etc/init.d/S99myhello chmod x ~/my_overlay/etc/init.d/S99myhello在make menuconfig中进入System configuration在Root filesystem overlay directories选项中填入你的overlay目录的绝对路径例如/home/yourname/my_overlay。重新构建。构建完成后你的S99myhello脚本就会出现在输出镜像的/etc/init.d/目录下并在系统启动时执行。方法二编写自定义 Buildroot package对于需要从源码编译的第三方软件你需要为其创建一个Buildroot package。这涉及在package/目录下创建一个新的目录并编写至少两个文件Config.in(用于menuconfig) 和mypackage.mk(构建规则)。这属于高级用法可以参考Buildroot手册和现有package的写法。6.3 调试内核与应用程序QEMU的强大之处在于其内置的调试支持。调试Linux内核在make menuconfig的Kernel菜单下确保Build kernel with debug symbols被勾选。同时在Kernel configuration子菜单中可以进一步调整内核配置例如关闭随机地址空间布局随机化KASLR以方便调试。重新构建内核 (make linux-rebuild) 或整个系统 (make)。使用以下命令启动QEMU并等待GDB连接qemu-system-aarch64 -M virt ... -s -S-s是-gdb tcp::1234的简写表示在1234端口开启GDB服务器-S表示启动后暂停CPU等待调试器介入。在另一个终端使用交叉编译器的GDB位于output/host/bin/aarch64-buildroot-linux-gnu-gdb连接./output/host/bin/aarch64-buildroot-linux-gnu-gdb output/build/linux-*/vmlinux (gdb) target remote localhost:1234 (gdb) continue现在你就可以像调试普通程序一样设置断点、单步执行内核代码了。调试用户空间程序在make menuconfig的Target packages-Debugging, profiling and benchmark中勾选gdb和gdbserver。重新构建并运行系统。在目标系统QEMU内启动你的程序并挂载gdbserver# 在QEMU内 gdbserver :2345 /path/to/your_program在主机上用交叉编译器的GDB连接./output/host/bin/aarch64-buildroot-linux-gnu-gdb /path/to/your_program (gdb) target remote 10.0.2.15:23457. 常见问题排查与性能优化即使按照步骤操作你也可能会遇到一些问题。这里列举几个我常遇到的1. 构建失败下载超时或校验和不匹配这是最常见的问题尤其是首次构建时。解决方案 Buildroot会尝试从上游镜像站下载网络不稳定时容易失败。可以手动将dl/目录下下载失败的文件删除然后重新执行make。对于顽固的包可以尝试使用代理在主机系统设置HTTP/HTTPS代理。手动下载根据构建输出中打印的URL用浏览器或下载工具手动下载文件放到dl/目录下再重新构建。更换镜像源修改package/目录下对应软件的.mk文件中的下载地址需一定经验。2. QEMU启动后卡住没有登录提示检查点1 确保QEMU命令中包含了-nographic和-append “consolettyAMA0”参数将输出重定向到串口。检查点2 内核命令行中的root参数指定的设备是否正确对于virtio-blk磁盘第一个设备是/dev/vda。对于其他模拟磁盘如ifsd可能是/dev/sda。检查点3 根文件系统镜像格式是否正确内核是否支持该文件系统如ext4可以在内核启动时按任意键进入U-Boot或内核命令行查看更详细的信息。3. 系统空间不足Buildroot默认生成的根文件系统很小可能只有几十MB。如果你安装了大量软件包可能会在构建或运行时提示空间不足。解决方案 在make menuconfig的Filesystem images菜单下找到exact size of the root filesystem (in MB)选项将其调大例如设为256或512。注意这增加的是镜像文件的大小不是运行时内存。4. 性能优化建议使用ccache 在make menuconfig-Build options中启用Enable compiler cache。这能显著加速二次及后续的编译。保留构建目录 默认情况下make clean会删除output/build/下的所有编译中间文件。如果只是修改了根文件系统配置如添加软件包可以只运行makeBuildroot会智能地只重新编译必要的部分。如果要彻底清理才用make clean。使用外部工具链 对于大型项目或团队协作可以考虑使用预编译好的、性能优化的外部工具链如Linaro GCC在Toolchain菜单中配置。这可以节省首次构建工具链的时间约15-30分钟。通过以上步骤你应该已经能够熟练地使用Buildroot和QEMU来构建、运行并调试一个自定义的Linux系统了。这套组合的价值远不止于“跑起来”它为你提供了一个完全可控的、可任意修改和实验的沙盒环境。无论是学习内核模块开发、测试新的系统服务还是为真实硬件做软件原型它都是一个不可或缺的利器。我自己的很多驱动调试和系统调优工作都是先在QEMU里验证通过才上真机的这节省了大量的时间和硬件成本。
返回列表