news 2026/9/3 1:43:00

U-Boot中make命令会发生什么?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
U-Boot中make命令会发生什么?

大家好,我是嵌入式兔哥。在嵌入式开发中,U-Boot的编译构建是核心基础环节,不少朋友对make命令的执行链路、中间文件生成及最终链接过程存在困惑。今天兔哥就带大家逐层拆解,把这些底层逻辑讲透,全是干货,建议收藏备用。

执行make命令会发生的流程如图:

一、U-Boot中make命令的完整执行流程

make无参数执行的核心目标是生成最终可烧录的二进制文件u-boot.bin,整个流程严格遵循顶层Makefile的依赖链,从默认目标开始逐层拆解,依次完成编译、链接、格式转换等操作,增量构建的核心就在于依赖关系的精准判断。

1.1 默认目标的触发与依赖传递

顶层Makefile首先定义默认目标为_all,核心代码如下:

PHONY := _all _all: # KBUILD_EXTMOD为空(不编译外部模块)时,_all依赖all目标 _all: all

由此形成“_all→all”的第一层依赖关系,all目标的核心依赖是$(ALL-y)集合,对应的Makefile代码的:

all: $(ALL-y) # 默认核心目标清单,随板级配置追加产物 ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check

该清单会根据板级配置(如CONFIG_SPL、CONFIG_ONENAND_U_BOOT)追加对应产物,整个流程最终围绕u-boot.bin的生成展开。

all目标的核心依赖是$(ALL-y)集合,这是编译的核心目标清单,默认包含u-boot.srec、u-boot.bin、u-boot.sym、System.map、u-boot.cfg等文件,同时会根据板级配置xxx_deconfig文件(如CONFIG_SPL、CONFIG_ONENAND_U_BOOT)追加对应产物,整个流程最终围绕u-boot.bin的生成展开。

1.2 u-boot.bin的生成链路拆解

u-boot.bin并非直接编译生成,而是经过多步格式转换和依赖联动得到,核心链路如下:

第一步:u-boot-nodtb.bin→u-boot.bin:当未启用设备树分离配置(CONFIG_OF_SEPARATE≠y)时,u-boot.bin的生成依赖u-boot-nodtb.bin,对应Makefile代码:

u-boot.bin: u-boot-nodtb.bin FORCE $(call if_changed,copy)

其中$(call if_changed,copy)调用scripts/Kbuild.include中的if_changed函数,仅当u-boot-nodtb.bin更新或命令变化时,执行copy操作生成u-boot.bin,实现增量构建。

第二步:u-boot(ELF文件)→u-boot-nodtb.bin:u-boot-nodtb.bin由ELF格式的u-boot经格式转换生成,Makefile代码如下:

u-boot-nodtb.bin: u-boot FORCE $(call if_changed,objcopy) $(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE)) $(BOARD_SIZE_CHECK)

核心逻辑是通过objcopy将ELF文件转为纯二进制文件,同时执行静态重定位(依赖CONFIG_SYS_TEXT_BASE指定的链接地址,如0x87800000)和板级大小检查,确保文件符合硬件限制。

第三步:核心依赖→u-boot(ELF文件):ELF格式的u-boot是链接核心产物,依赖启动目标码、合并目标文件和链接脚本,Makefile代码:

u-boot: $(u-boot-init) $(u-boot-main) u-boot.lds FORCE $(call if_changed,u-boot__)

三大核心依赖分别是:u-boot-init(即(head−y),对应arch/arm/cpu/armv7/start.o启动目标码)、u−boot−main(即(head-y),对应arch/arm/cpu/armv7/start.o启动目标码)、u-boot-main(即(heady),对应arch/arm/cpu/armv7/start.o启动目标码)、ubootmain(即(libs-y),各子目录built-in.o集合)、u-boot.lds链接脚本;$(call if_changed,u-boot__)封装链接命令,最终通过链接器组合生成ELF文件。

第四步:链接脚本u-boot.lds的生成:链接脚本决定内存布局,由模板经预处理生成,Makefile代码:

u-boot.lds: $(LDSCRIPT) prepare FORCE $(call if_changed_dep,cpp_lds)

其中$(LDSCRIPT)是板级指定的链接脚本模板,prepare目标完成编译准备(如生成配置头文件),cpp_lds通过C预处理器展开模板中的宏定义和条件编译,生成最终可用的u-boot.lds。

二、目标文件(.o)

2.1 .o文件的生成来源

所有.o文件均由源代码编译生成,分为两类:一是单个模块.o文件,由.c源文件或.S汇编文件通过交叉编译器编译得到,核心命令如下:

# 简化命令,实际含-I(头文件路径)、-O(优化等级)等参数arm-linux-gnueabihf-gcc -c -o mxc_gpio.o mxc_gpio.c

比如drivers/gpio/mxc_gpio.c编译生成mxc_gpio.o;二是合并后的built-in.o文件,由各子目录下所有单个.o文件经部分链接生成,是后续顶层链接的核心输入。

2.2 built-in.o的合并过程

每个核心子目录(如cmd/、drivers/、fs/)都会生成built-in.o,以drivers/gpio/built-in.o为例,对应的编译命令:

cmd_drivers/gpio/built-in.o := arm-linux-gnueabihf-ld.bfd -r -o drivers/gpio/built-in.o drivers/gpio/mxc_gpio.o

通过交叉链接器ld的-r参数(部分链接),将目录下所有单个.o文件合并为可重定向的built-in.o。顶层Makefile通过libs-y变量统一收集:

# 定义需编译的核心子目录 libs-y += lib/ cmd/ common/ drivers/ fs/ net/ ... # 转换为各目录的built-in.o libs-y := $(patsubst %/, %/built-in.o, $(libs-y))

最终形成u-boot-main依赖集,大幅简化顶层链接的依赖管理。

三、最终链接过程详解

链接是将分散的目标文件、启动文件和链接脚本组合为可执行文件的过程,也是决定程序在内存中运行布局的关键步骤,兔哥带大家看具体细节。

3.1 链接的输入与核心参数

链接的输入文件包括:start.o启动目标码、所有子目录built-in.o集合、u-boot.lds链接脚本;交叉链接器(如arm-linux-gnueabihf-ld.bfd)的完整链接命令如下:

arm-linux-gnueabihf-ld.bfd -pie --gc-sections -Bstatic -Ttext 0x87800000\-o u-boot -T u-boot.lds\arch/arm/cpu/armv7/start.o\--start-group arch/arm/cpu/built-in.o arch/arm/imx-common/built-in.o...(所有built-in.o)--end-group\-L /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/4.9.4\-lgcc -Map u-boot.map

核心参数解析如下:

  • -T u-boot.lds:指定链接脚本,控制段布局;

  • -Ttext 0x87800000:指定代码段起始地址,与CONFIG_SYS_TEXT_BASE保持一致;

  • –gc-sections:垃圾回收未使用的代码/数据段,减小文件体积;

  • –start-group/–end-group:解决组内文件交叉依赖,循环解析符号;

  • -lgcc:链接GCC内置库,提供底层运算和异常处理函数;

  • -Map u-boot.map:生成链接映射文件,记录符号地址,用于调试。

3.2 链接输出与后续转换

链接直接输出ELF格式的u-boot文件,该文件含符号表和调试信息,可用于调试但无法直接烧录。后续通过objcopy转换为纯二进制的u-boot-nodtb.bin,再经copy操作生成最终的u-boot.bin,完成整个构建流程。

四、核心文件及作用对比表

文件名称生成来源核心作用文件格式/类型
顶层Makefile项目自带,板级适配修改定义编译目标、依赖关系、工具链参数,控制整体构建流程Makefile脚本文件
.c/.S文件开发者编写的源代码(驱动、命令、启动代码等)嵌入式程序核心逻辑载体,编译的原始输入源代码文件
.o文件.c/.S文件经交叉编译器(gcc)编译生成单个模块的目标文件,含二进制指令,为后续链接提供输入目标文件(可重定向)
built-in.o文件同一子目录下多个.o文件经ld -r部分链接生成合并子目录模块,简化顶层链接的依赖管理合并目标文件(可重定向)
u-boot.lds板级链接脚本模板经cpp_lds预处理生成定义代码段、数据段、栈地址等内存布局,指导链接过程链接脚本文件
u-boot(ELF文件)start.o、built-in.o、u-boot.lds经链接器链接生成含符号表和调试信息,为后续格式转换提供基础ELF可执行文件(带调试信息)
u-boot-nodtb.binELF格式u-boot经objcopy转换生成纯二进制文件,已完成静态重定位,适配硬件内存地址纯二进制文件
u-boot.binu-boot-nodtb.bin经copy操作生成最终可烧录文件,用于嵌入式设备启动引导纯二进制文件(可烧录)
u-boot.map链接过程中生成(-Map参数控制)记录符号地址、段布局信息,用于程序调试和问题定位文本格式映射文件

总结

兔哥再帮大家梳理核心逻辑:U-Boot的make构建流程本质是“依赖链驱动的增量构建”,从默认目标逐层拆解至源代码编译,经“.c/.S→.o→built-in.o→ELF文件→二进制文件”的转换链路,最终生成可烧录的u-boot.bin。其中.o文件是编译与链接的核心中间载体,u-boot.lds决定内存布局,链接过程则是整合所有模块的关键步骤。掌握这些逻辑,能帮大家快速定位编译和启动过程中的各类问题,深入理解嵌入式程序的构建本质。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/3 0:01:57

SQL性能瓶颈破局:Explain分析+实战优化全攻略

SQL性能瓶颈破局&#xff1a;Explain分析实战优化全攻略你是否曾为数据库查询性能低下而苦恼&#xff1f;面对复杂的业务场景&#xff0c;如何快速定位查询瓶颈并实施优化&#xff1f;本文将通过一系列真实案例&#xff0c;带你深入剖析SQL查询优化的精髓&#xff0c;从Explain…

作者头像 李华
网站建设 2026/9/3 0:39:44

深入解析 C# async/await 执行原理:从语法糖到状态机

异步编程是C#开发中提升程序吞吐量的核心手段&#xff0c;而async/await作为异步编程的“语法糖”&#xff0c;极大简化了异步代码的编写逻辑。但多数开发者仅停留在“会用”层面&#xff0c;对其底层执行原理、状态机的工作机制一知半解。本文将从业务代码执行流程到状态机底层…

作者头像 李华
网站建设 2026/9/2 23:45:36

鸿蒙6核心功能实战:手把手教你开发分布式协同小应用

鸿蒙6核心功能实战&#xff1a;手把手教你开发分布式协同小应用 鸿蒙6的核心优势在于分布式协同能力——能让手机、平板、智慧屏等设备突破硬件边界&#xff0c;实现数据和功能的无缝流转。本文以“手机平板文件无缝传输”为例&#xff0c;手把手拆解鸿蒙6分布式软总线、设备管…

作者头像 李华
网站建设 2026/9/3 1:32:12

【开题答辩全过程】以 共享单车管理系统为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

作者头像 李华
网站建设 2026/8/30 12:17:34

java计算机毕业设计校园车辆门禁管理系统 高校智能车行闸机云平台的设计与实现 基于SpringBoot的校园车辆出入与收费一体化系统

计算机毕业设计校园车辆门禁管理系统8d42u9&#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。校门早高峰堵成停车场、外来车蹭车位、临时车人工填单——传统纸质登记对讲机模式让保…

作者头像 李华