ARTICLE DETAIL

资讯详情

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

RK3568嵌入式Linux系统裁剪实战:用Buildroot构建量产级BSP

RK3568嵌入式Linux系统裁剪实战:用Buildroot构建量产级BSP 上个月帮客户调一批基于RK3568的工控盒子硬件接口、外壳都定了唯独系统还停在厂商SDK默认的桌面版Ubuntu上。启动慢、镜像大、还塞了一堆用不上的组件客户要求三个月内把系统精简到秒开、稳定、可量产我最后把所有方案摊开对比了一遍还是决定用Buildroot重新构建一版。这篇文章就是把从配置到部署的完整流程记录下来包括我在内核、设备树、根文件系统上踩过的坑以及最终量产的烧录方式。RK3568这块芯片在工控、边缘计算、商业显示里出镜率越来越高Buildroot又是嵌入式Linux定制里最“轻”的构建系统。如果你想把系统裁剪干净、启动时间压到几秒、镜像控制在几百MB以内或者需要固定一版与硬件强绑定的BSP那这套流程值得看完。1. 为什么选这套方案RK3568平台特点和Buildroot的取舍1.1 RK3568/RK3566平台到底适合做什么RK3568是瑞芯微面向AIoT和工业应用推出的一颗SoC四核Cortex-A55架构主频最高2.0GHz内置Mali-G52 GPU和0.8TOPS算力的NPU。视频解码支持到4K H.265/H.264显示接口有LVDS、MIPI DSI、eDP、HDMI外围接口更是给得相当大方PCIe、SATA、双千兆以太网、多路CAN、多路UART还有USB 3.0。很多朋友分不清RK3568和RK3566这里顺便说下。 RK3566和RK3568的CPU、GPU、NPU规格几乎一样主要区别在外设RK3568多出PCIe 3.0、SATA 3.0、双千兆MAC整体定位更偏工业、NAS、边缘服务器RK3566更多出现在平板、学习机、HMI这类消费或轻工业产品上接口砍掉了一些成本更低。如果你的项目需要接PCIe网卡、SATA硬盘或者做多网口网关选RK3568更合适。这套平台的实际应用场景非常广。我做过和接触过的就有工业HMI人机界面用LVDS或HDMI接屏走CAN或Modbus控制设备边缘计算网关双千兆网口做主备或内外网隔离跑轻量容器商业显示广告机支持4K视频循环播放远程管理NAS存储SATA接硬盘跑Samba和下载服务视觉检测设备MIPI CSI接摄像头NPU做人脸检测或缺陷识别这些场景对系统的一个共同要求是不要臃肿不要无关组件启动要快运行要稳。厂商SDK自带的桌面系统在这类产品里反而成了负担。1.2 Buildroot vs Yocto vs 手工交叉编译给RK3568做Linux系统行业内最主流的路线有三条Buildroot、Yocto、手工脚本交叉编译。我三套都试过说下真实的体感。手工交叉编译最灵活但也是最折磨人的。你需要在宿主机上配置交叉工具链然后一个个去下载U-Boot、内核、BusyBox、各种应用库手动编译再手动打包。每次升级一个组件依赖关系都可能炸。适合只想快速验证某一个启动阶段的情况不适合做长期维护的产品。Yocto功能最强BitBake的配方机制适合超大项目包管理系统成熟社区和企业支持都很到位。但代价是学习曲线极其陡峭构建时间长得出名第一次全量编译经常要几个小时到十几个小时磁盘占用也轻松超过100GB。如果团队只有一两个人做BSPYocto很容易变成项目进度的黑洞。Buildroot刚好卡在中间。它基于Makefile和Kconfig配置方式类似内核的menuconfig用一套统一的框架管理交叉工具链、U-Boot、内核和根文件系统。一条make命令就把镜像构建出来配置文件可以版本化管理一次配置到处复现。对比项BuildrootYocto手工交叉编译构建速度快增量编译体验好慢首次构建考验耐心看脚本水平一般慢学习成本中低menuconfig方式易上手高需要理解BitBake体系高依赖扎实的Linux功底包管理内置数千个软件包配方极其完善没有定制灵活性中等rootfs overlay机制很实用极高适合复杂定制最高但也最累产品维护适合中小团队长期维护适合大型团队不建议用于产品我最终的结论是对于RK3568这种资料相对开放、官方提供了完整BSP仓库的平台Buildroot是性价比最高的方案。它不会像Yocto那样消耗大量时间又能把内核、U-Boot、根文件系统这三层统一管理起来。1.3 这套流程适合谁写这篇文章不是为了让所有人照着敲命令而是帮助你判断自己是否适合走Buildroot这条路。如果你的情况符合下面任何一条这套流程就值得你花时间正在为一个具体产品做BSP需要清理厂商SDK里的无用组件对启动时间有要求想把系统启动压到5秒以内需要稳定的、可重复构建的镜像避免手工配环境导致“换台电脑就编不过”想从瑞芯微官方SDK的复杂脚本里走出来用更标准的方式管理内核与文件系统团队需要快速迭代经常要调整内核配置、设备树和业务程序并生成可烧录镜像如果你只是想做应用层开发完全不需要动内核和系统那Buildroot对你来说有点大材小用了。但如果公司的产品涉及硬件定制、系统裁剪、量产烧录那这套流程几乎是必经之路。2. 开工前的准备工作主机环境、源码下载和目录规划2.1 编译主机的依赖与环境Buildroot对编译主机的要求不复杂但缺了依赖会中途报各种莫名其妙的错。我习惯用Ubuntu 22.04 LTS做编译机Debian 12也没问题别的发行版注意手动补齐依赖。在干净的Ubuntu系统上先执行依赖安装sudo apt update sudo apt install -y sed make binutils build-essential gcc g bash patch \ gzip bzip2 perl tar cpio unzip rsync wget file bc python3 \ libncurses-dev libssl-dev这里有几个关键依赖值得多说一句。libncurses-dev是menuconfig文本图形界面需要的少了它make menuconfig会报错libssl-dev在编译U-Boot和部分内核工具时是硬性要求python3则是现在很多构建脚本的运行时依赖。缺哪个装哪个通常也能往后推但每次中断都要重新进入构建流程浪费时间。磁盘空间至少要预留50GB。Buildroot的编译过程会下载源码包、生成host工具、编译交叉工具链第一次全量编译后目录体积轻松超过20GB再加上dl目录和以后可能放的多个输出目录50GB比较稳妥。2.2 Buildroot的dl目录和外部树机制Buildroot有两个机制我建议提前理解dl目录和外部树。dl目录是Buildroot下载源码包的缓存目录。首次构建时它会通过wget从各个上游地址拉取源码压缩包这些文件会统一缓存在dl目录下之后所有版本的构建都能复用。假如你手头有多个项目每个项目都独立下载一遍源码包既慢又浪费带宽。通过BR2_DL_DIR环境变量可以指定统一的下载缓存export BR2_DL_DIR/opt/buildroot-dl外部树是Buildroot官方推荐的扩展机制。它允许你把项目相关的配置、软件包配方、rootfs overlay、post-build脚本放到一个独立目录与Buildroot主目录分离。升级Buildroot版本时不影响你的项目文件。一个标准的外部树目录结构大致如下br2-external-rk3568/ ├── Config.in ├── external.desc ├── external.mk ├── board/ │ └── rk3568/ │ ├── rootfs-overlay/ │ ├── post-build.sh │ ├── post-image.sh │ └── genimage.cfg └── package/ └── custom-app/通过BR2_EXTERNAL环境变量加载外部树make BR2_EXTERNAL/path/to/br2-external-rk3568 rockchip_rk3568_defconfig我的习惯是即使最开始只有一个配置文件也把项目放到外部树里管理。这样Buildroot本体可以随时换成新版或新版本分支项目定制部分始终独立不会在make clean时被误删。2.3 获取Buildroot与BSP源码Buildroot本体建议用git克隆然后切到某个长期支持版本。我目前用的版本线是2024.02.x属于LTS分支稳定性比较好git clone https://gitlab.com/buildroot.org/buildroot.git cd buildroot git checkout 2024.02.xRK3568的BSP源码主要是两个仓库瑞芯微官方维护仓库地址我直接给出来# 内核 git clone https://github.com/rockchip-linux/kernel.git -b develop-5.10 # U-Boot git clone https://github.com/rockchip-linux/u-boot.git -b next-devBuildroot本身并不需要你把内核和U-Boot提前克隆到本地它会在配置完成后自己下载。但我习惯先手动拉一份做设备树开发和内核配置实验因为脱离了Buildroot环境去改内核设备树编辑、编译、验证的速度更快。等改得差不多了再让Buildroot按照配置去拉同一份源码。内核版本的选择上瑞芯微官方维护的5.10分支是目前RK3568支持最完整、坑最少的一个版本新内核虽然也支持RK3568但很多BSP层面的补丁和驱动没跟上量产项目没必要冒这个险。3. 配置阶段核心步骤从defconfig到menuconfig逐项拆解3.1 先定位到Rockchip平台与CPU架构Buildroot的配置分为两层第一层是目标平台的整体配置第二层是内核和U-Boot自身的配置。整体配置通过make menuconfig完成。先看Buildroot自带的RK3568 defconfig是否适配你的版本。 有些版本自带rockchip_rk3568_defconfig直接加载即可make rockchip_rk3568_defconfig如果没有对应的defconfig那就用menuconfig手动配置这也是我更推荐的方式因为你能清楚地知道每一项改动意味着什么make menuconfig进入menuconfig后第一站是Target options。RK3568是64位ARM处理器这里需要确认Target ArchitectureAArch64 (little endian)Target Architecture Variantcortex-a55Target Architecture如果不小心选成ARM (little endian)后面编译出来的内核在RK3568上根本跑不起来。这类低级错误我见过不止一次排查起来还容易忽略。接着进入Bootloaders勾选U-Boot并指定U-Boon的board defconfig为evb-rk3568。如果你用的是自己设计的板卡SDK里一般会根据你的硬件提供对应的defconfig或者你基于evb-rk3568修改。3.2 Toolchain内建还是外置配置完目标架构后下一个关键决策是Toolchain。Buildroot支持内建工具链和外置工具链两种方式。内建工具链就是让Buildroot从零编译一套交叉编译器过程耗时较长但好处是完全可控工具链版本与内核版本可以精确搭配。外置工具链则是直接指定一套已编译好的交叉编译器例如Linaro的AArch64工具链速度快但版本兼容性需要自己保证。对于RK3568量产项目我推荐优先使用Buildroot内建工具链。原因很简单可复现性。同一个Buildroot版本加上同一个配置在任意主机上构建出来的工具链是一致的。外置工具链虽然快但工具链的版本差异在后期排查编译问题时会变成一个新的变量。如果必须使用外置工具链记得勾选对应的C library。RK3568平台的glibc是主流选择uClibc-ng和musl虽然体积小但很多商业库和驱动没有适配不推荐在产品里冒险。3.3 System configuration与登录体验System configuration是定制系统“人味”的一层。我需要设置主机名、root密码、登录串口等基础参数。RK3568开发板的调试串口常见的是ttyS0或ttyS2这个要看具体板卡的硬件设计。我的方法是在开发板资料里查UART的dts配置确定调试串口设备节点。如果选错系统起来后只会在错误的串口上输出日志串口工具完全看不到任何信息。登录名和密码方面量产设备建议直接关闭root密码的远程登录或者改成密钥认证。但开发阶段为了方便我还是会设置一个临时root密码。注意Buildroot的root密码是明文形式写入配置文件的密码在生产前一定要替换或禁用。系统配置里还有一个容易忽略的设置getty自动登录选项。开发阶段可以开启自动登录省去每次输密码。量产前一键关闭避免任何人拿到串口就能直接进系统。3.4 内核、U-Boot和文件系统镜像的统一入口Buildroot的厉害之处在于内核、U-Boot、根文件系统和应用软件包都是在同一个menuconfig里配置的。内核配置在Kernel菜单里。RK3568平台需要选择自定义git仓库手动填写内核源码的仓库地址和分支并指定内核的defconfig为rockchip_linux_defconfig。同时勾选DTS支持指定设备树文件路径为rockchip/rk3568-evb.dts如果你的板卡是自己设计的则指定你自定义的dts。U-Boot配置在Bootloaders菜单里同样选择自定义git仓库填入官方U-Boot仓库和分支并设置板级defconfig。RK3568 EVB板卡一般用evb-rk3568。Filesystem images菜单决定了根文件系统最终打包成什么格式。RK3568平台最常用的是ext4和squashfs。ext4适合需要频繁读写rootfs的场景squashfs是只读压缩文件系统适合系统与数据分离的产品架构。我的习惯是产品量产包用squashfs做rootfs开发阶段用ext4修改根文件系统内容更方便。这些配置项分散在不同菜单里但最终都会汇总到根目录的.config文件里。保证所有配置一条命令可复现是Buildroot的核心价值所在。3.5 保存配置savedefconfig的正确姿势配置完成后直接退出保存会用完整的.config文件里面包含大量默认值不适合版本管理。正确的做法是使用savedefconfig生成精简的defconfigmake savedefconfig这个命令会生成一个只有非默认配置项的defconfig默认路径在Buildroot根目录的defconfig文件中。把它复制到configs目录并命名为rockchip_rk3568_custom_defconfig之后就通过这个名字加载配置。我个人的实践是把项目的defconfig直接放在外部树里配合BR2_EXTERNAL使用。即使Buildroot主目录换版本项目配置也依然可以干净地加载。4. 内核、设备树与底层定制RK3568硬件适配的细活4.1 内核配置的两种姿势Buildroot里的内核配置有两种方式一种是在make menuconfig的Kernel菜单里指定内核defconfig然后直接编译另一种是先在内核源码目录里手动配置再把配置固化到Buildroot。我常用的做法是cd output/build/linux-custom/ make ARCHarm64 rockchip_linux_defconfig make ARCHarm64 menuconfig make ARCHarm64 savedefconfig改完内核配置后把生成的defconfig文件覆盖到内核源码目录并在Buildroot的Kernel菜单里指定BR2_LINUX_KERNEL_CUSTOM_GITy BR2_LINUX_KERNEL_CUSTOM_REPO_URLhttps://github.com/rockchip-linux/kernel.git BR2_LINUX_KERNEL_CUSTOM_REPO_VERSIONdevelop-5.10 BR2_LINUX_KERNEL_DEFCONFIGrockchip_linux_defconfig这种方式的好处是内核配置的每一处改动都是显式的不会在Buildroot构建过程中丢失。我就遇到过直接在Buildroot的menuconfig里改内核配置结果重新编译时配置被上游defconfig覆盖的情况折腾了半天才想通。内核配置阶段的坑还有一个RK3568的内核需要打开CONFIG_ROCKCHIP_IOMMU、CONFIG_ROCKCHIP_WATCHDOG等平台相关选项这些选项在rockchip_linux_defconfig里已经默认开启。如果你基于其他defconfig修改内核务必确认这些平台驱动没有被裁剪掉。4.2 设备树定制以添加OV5695摄像头为例RK3568的设备树修改是底层适配的核心工作几乎所有硬件外设的调整都在dts里体现。瑞芯微官方SDK会提供完整的dts文件路径通常位于arch/arm64/boot/dts/rockchip/rk3568-evb.dts如果你的板卡改动大建议复制一份dts命名为自己项目的名字并同步在Rockchip的Makefile里注册该文件名。以摄像头适配为例很多RK3568项目都需要接入MIPI CSI摄像头传感器比如OV5695、OV8858这类型号。设备树里需要配置I2C地址、MCLK时钟、复位GPIO、电源引脚和CSI DPHY通道。下面是一个典型的OV5695设备树配置示例i2c4 { status okay; clock-frequency 400000; ov5695: ov569536 { compatible ovti,ov5695; reg 0x36; clocks cru CLK_MIPICAM_OUT; clock-names xvclk; pinctrl-names default; pinctrl-0 mipicam_pwdn_gpio; reset-gpios gpio2 RK_PB6 GPIO_ACTIVE_HIGH; pwdn-gpios gpio2 RK_PB6 GPIO_ACTIVE_HIGH; rockchip,camera-module-index 0; rockchip,camera-module-facing back; rockchip,camera-module-name default; rockchip,camera-module-lens-name default; port { ov5695_out: endpoint { remote-endpoint mipi_in_ucam0; >make ARCHarm64 dtbs确认dts语法无误再通过Buildroot整体编译。4.3 U-Boot阶段要注意的东西U-Boot负责硬件初始化和引导内核定制点主要集中在环境变量、bootargs和启动流程。RK3568的U-Boot默认会从存储介质读取参数分区环境变量也存放在这里。如果你需要固定内核的启动参数例如指定console、root分区位置可以在U-Boot的defconfig或者board头文件里设置默认环境变量。我通常会在U-Boot阶段设置以下参数bootargsearlyconuart8250,mmio32,0xfe660000 consolettyS2,1500000 root/dev/mmcblk0p5 rootfstypeext4 rw这里需要特别留意console参数与实际使用的调试串口匹配。RK3568的调试串口在不少开发板上用的是ttyS2波特率有的是115200有的是1500000以板卡原理图为准。串口参数不对时内核起来后不会有任何输出或者输出乱码。U-Boot阶段还有一个容易踩的坑是logo和显示初始化。如果你的产品带屏幕U-Boot需要初始化显示控制器才能在开机瞬间显示logo这涉及到U-Boot里的显示驱动配置。如果不需要开机logo可以直接在板级配置里关闭显示初始化减少启动时间。5. 定制根文件系统把业务装进去5.1 rootfs overlay最实用的定制手段Buildroot生成根文件系统的机制是先构建一个基础rootfs再依据配置安装软件包最后把rootfs overlay目录里的内容覆盖进去。这个特性就是定制文件系统的核心手段。在外部树的board/rk3568/rootfs-overlay目录下可以按最终rootfs的目录结构放置文件。例如rootfs-overlay/ ├── etc/ │ ├── init.d/ │ │ └── S99custom │ ├── fstab │ ├── profile │ └── network/ │ └── interfaces ├── opt/ │ ├── app/ │ │ └── my_application │ └── config/ │ └── app.conf └── usr/ └── local/ └── bin/ └── my_tool然后在Buildroot配置里指定BR2_ROOTFS_OVERLAY$(BR2_EXTERNAL_RK3568_PATH)/board/rk3568/rootfs-overlayrootfs overlay里的文件会原样拷贝到目标rootfs的对应路径中。业务可执行文件、配置文件、启停脚本都可以通过这个机制进入最终镜像。启动脚本的命名需要注意Buildroot默认的init系统会用/etc/init.d/S??name方式执行启动脚本数字决定执行顺序。比如S99custom会在所有默认服务之后执行适合放业务主程序。5.2 常用应用软件包怎么选Buildroot自带数千个软件包绝大多数需求都能通过make menuconfig的Target packages菜单勾选解决。RK3568平台我常用的软件包组合如下dropbear轻量级SSH服务端比openssh体积小很多ethtool调试网口参数必须iperf3网络性能测试nfs-utils开发阶段挂载NFSalsa-utils音频调试mtd-utils管理NAND/NOR Flashtcpdump抓包排查网络can-utils调试CAN总线strace跟踪用户空间系统调用开发阶段软件包可以适当多装量产版本尽量精简reduce攻击面和小体积。每多一个软件包出问题的概率和系统启动时间都会增加一份。这里提一个工控场景的特殊需求如果你需要在RK3568上运行EtherCAT IGH主站Buildroot主线原生不带IGH的配方需要通过BR2_EXTERNAL外部包机制自行编写包配方。IGH依赖Xenomai或RT Patch内核配置复杂度比普通软件包高不少。我的建议是先确认IGH的版本与内核RT补丁版本的匹配关系再进行移植否则在运行时会卡在实时性测试上。5.3 构建后期处理post-build与post-image脚本除了rootfs overlayBuildroot还提供post-build脚本和post-image脚本用于在rootfs打包前和镜像生成后做额外处理。post-build脚本通常用来调整rootfs里的文件权限、删除开发残留文件、生成动态配置。一个典型的例子是将root用户的ssh key放进去或者删除编译产生的日志。下面是一个post-build.sh的示例#!/bin/bash TARGET_DIR$1 # 禁止root远程密码登录 sed -i s/^PermitRootLogin.*/PermitRootLogin prohibit-password/ \ $TARGET_DIR/etc/ssh/sshd_config # 删除开发残留的编译工具 rm -rf $TARGET_DIR/usr/lib/libstdc* # 写入系统版本信息 echo rk3568-edge-v1.0.0-$(date %Y%m%d) $TARGET_DIR/etc/versionpost-image脚本则是在Buildroot生成完整镜像后执行常用来调用genimage生成可烧录的完整镜像。我在脚本里会做两件事调用genimage根据分区表生成sdcard.img以及把U-Boot、内核、rootfs分别拷贝到一个打包目录方便量产烧录。Buildroot会在构建结束时自动调用这些脚本通过配置指定BR2_ROOTFS_POST_BUILD_SCRIPT$(BR2_EXTERNAL_RK3568_PATH)/board/rk3568/post-build.sh BR2_ROOTFS_POST_IMAGE_SCRIPT$(BR2_EXTERNAL_RK3568_PATH)/board/rk3568/post-image.sh脚本记得加执行权限否则Buildroot会报错。6. 编译构建与烧录部署从make到上电启动6.1 首次编译与增量编译一切配置就绪后编译命令很简单make -j$(nproc)第一次全量编译的时间取决于主机性能在我的机器上大概需要20到40分钟其中交叉工具链的编译最耗时。之后的增量编译会快很多每次只编译改动的部分通常几分钟就能完成。编译过程中最容易遇到的问题是网络下载慢或失败。Buildroot在构建时会从网上下载大量的源码包如果某个包的下载地址超时整个构建会中断。我的经验是预先通过BR2_DL_DIR把常用源码包缓存好或者借助国内镜像源加速下载。配置完镜像源后重新执行make即可。编译完成后产物在output/images目录下output/images/ ├── boot.vfat ├── rk3568-evb.dtb ├── Image ├── rootfs.ext4 ├── rootfs.squashfs ├── sdcard.img ├── u-boot.bin ├── u-boot.dtb └── u-boot.img6.2 镜像产物与分区规划RK3568的分区规划是烧录前必须想清楚的一步。瑞芯微的方案通过parameter.txt描述分区表常见分区如下FIRMWARE_VER: 1.0 MACHINE: RK3568 CMD: mtdpartsrk29xxnand:0x000020000x00004000(uboot),0x000020000x00006000(misc),0x000100000x00008000(boot),0x000100000x00018000(recovery),0x000200000x00028000(backup),0x000400000x00048000(rootfs),-0x00088000(userdata)这里的单位是sector。uboot分区从sector 0x4000开始长度0x2000boot分区存放内核Image和dtbrootfs分区存放根文件系统镜。分区大小必须与实际生成的文件大小匹配否则烧录时会出现空间不足的报错。如果使用Buildroot生成的sdcard.img可以跳过分区规划直接烧录整卡镜像。但对于eMMC量产还是需要一份正确的parameter.txt。6.3 烧录到eMMC和TF卡RK3568支持多种烧录方式量产常用瑞芯微的RKDevToolWindows版或upgrade_toolLinux版。在Linux环境下的烧录命令大致如下upgrade_tool db rk3568_loader_v1.15.112.bin upgrade_tool ul rk3568_loader_v1.15.112.bin upgrade_tool di -p parameter.txt upgrade_tool di -uboot u-boot.img upgrade_tool di -boot boot.img upgrade_tool di -rootfs rootfs.ext4 upgrade_tool rdloader文件名根据你的BSP版本确定可以从瑞芯微SDK的RockchipTools目录里找到。如果设备进入loader模式失败可以先在开发板上进maskrom模式再重新执行烧录。如果只是调试阶段想快速验证直接烧TF卡更简单。Buildroot生成的sdcard.img可以一键写入TF卡sudo dd ifoutput/images/sdcard.img of/dev/sdX bs4M convfsync注意of/dev/sdX里X对应你的TF卡设备符千万别写错。我见过有同事把整个磁盘都覆盖的惨剧血的教训刷机之前一定先lsblk确认设备名。6.4 串口登录与上线验证系统烧录完成后用串口连接开发板的调试串口波特率按板卡设计设置常见的是115200或1500000picocom -b 1500000 /dev/ttyUSB0系统启动后你会看到U-Boot日志、内核日志最后进入login提示符或直接进入shell。进入系统后我基本会按这个顺序验证查看CPU信息cat /proc/cpuinfo确认四核A55查看内存free -h确认DDR容量查看网络ifconfig确认网口地址查看存储df -h确认rootfs分区挂载正常运行业务程序确认依赖库和权限没有问题查看dmesg确认没有驱动报错看到echo “hello rk3568”能在串口上正常输出整套构建流程算是跑通了。7. 常见问题与排查经验速查7.1 编译期问题下载慢、工具链报错编译期最常见的问题是Buildroot源码包下载失败。很多上游源码地址在国外拉取速度不稳定解法是给Buildroot配置镜像源而不是反复重试同一个地址。设置BR2_PRIMARY_SITE环境变量或直接在.config里配置镜像后下载速度会快很多。接着就是host工具版本问题。如果编译主机太老比如还是Ubuntu 18.04可能会遇到某些源码包需要更高版本host工具的情况。建议编译机保持系统更新至少Ubuntu 20.04以上。Buildroot对host工具的版本要求通常会在配置阶段检查如果检测不通过会给出明确的版本信息按提示升级即可。工具链报错还有一个典型场景同时存在多个交叉工具链时环境变量CC、CXX被污染导致内核或U-Boot用了错误的编译器。Buildroot默认会清理这些环境变量但如果你在自己的脚本里显式导出了CC反而会覆盖Buildroot的设置。排查时可以用make V1查看完整编译命令确认gcc路径是否指向Buildroot的output目录。7.2 启动期问题内核卡住、rootfs挂载失败系统启动阶段的问题排查主要靠串口日志。U-Boot启动后没有任何输出大概率是loader阶段出了问题需要检查loader版本和DDR初始化参数是否匹配板卡。内核启动卡在Starting kernel之后通常是内核启动参数问题。console参数、内存大小、设备树里的DDR配置不匹配都会导致内核起不来。可以在U-Boot环境变量里临时修改bootargs逐项排查。rootfs挂载失败的典型表现是内核启动后报VFS: Unable to mount root fs。原因主要有两类根文件系统分区的设备节点路径不对或文件系统类型与bootargs中指定的rootfstype不一致。检查partitions列表、内核配置里是否打开了对应的文件系统驱动以及设备树中分区起始地址是否与parameter.txt一致。还有一个特别隐蔽的问题内核解压后找不到rootfs提示No working init found。这通常是因为rootfs overlay里的init脚本权限不对或/etc/inittab配置错误。检查rootfs里/sbin/init是否存在以及rcS脚本是否有可执行权限。7.3 迭代开发时的效率技巧最后分享几个能明显提升迭代效率的小技巧。第一savedefconfig一定要养成习惯。每次配置改动后执行make savedefconfig把精简配置保存到外部树既方便版本管理也方便同事之间同步。第二Buildroot的包级重编命令非常实用。改了一个软件包或rootfs overlay文件后不需要全量编译只需要执行make package-rebuild make package-reconfigure这会跳过该包的下载和解压阶段直接重新编译速度提升非常明显。改rootfs overlay文件后直接make重新打包rootfs即可耗时只有几十秒。第三内核和U-Boot的开发效率更高。我会先在内核源码目录里独立编译验证确认无误后再让Buildroot使用同一个源码目录构建。通过在.config里指定BR2_LINUX_KERNEL_CUSTOM_GIT和BR2_LINUX_KERNEL_CUSTOM_REPO_VERSION指向本地已验证的commit这样既能快速迭代又保证了最终镜像的可复现性。第四量产版本一定要把debug接口关干净。Buildroot的Target packages里有一些调试工具量产前逐个排查是否还需要。root登录密码、调试串口getty配置、内核的magic sysrq功能都要按量产标准收口。我一般会针对量产版本单独保存一份defconfig与开发版配置区分开。最后再分享一个习惯每次完成一版可烧录的镜像我都会把commit哈希、内核版本、构建时间写进rootfs里的/etc/version文件。设备上线后如果出现问题只要看到这个文件就能精确定位到编译时的代码版本排查效率会高很多。
返回列表