欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 文化 > Uboot顶层Makefile文件分析

Uboot顶层Makefile文件分析

2025/3/16 11:55:16 来源:https://blog.csdn.net/weixin_54930908/article/details/144933176  浏览:    关键词:Uboot顶层Makefile文件分析

Uboot顶层Makefile文件分析

文章目录

  • Makefile前期文件处理
    • 版本号
    • MAKEFLAGS 变量
    • 命令输出
    • 静默输出
    • 编译结果输出目录
    • 代码检查
    • 模块编译
    • 获取主机架构和系统
    • 设置目标架构和交叉编译器
    • 调用 scripts/Kbuild.include
    • 导出其他变量
  • make xxx_defconfig 过程
    • 顶层Makefile初始化
    • 处理配置目标
    • 依赖项处理
      • **scripts_basic**
      • **outputmakefile**
      • **FORCE**
    • **调用 `scripts/Makefile.build`**
      • **cripts_basic 的处理**
      • **%config 的处理**
      • 总结
    • 生成 `.config` 文件
  • **`make` 命令全过程解析**
    • **概述**
    • **默认目标 `_all`**
    • **目标 `all` 的依赖**
    • **生成 `u-boot.bin`**
      • **u-boot.bin 的依赖**
      • **u-boot-nodtb.bin 的依赖**
      • **u-boot 的依赖**
      • **链接过程**
    • 总结

Makefile前期文件处理

版本号

  • 作用:定义 U-Boot 的版本号。方便开发者和管理者了解当前使用的 U-Boot 版本。

    • 版本号是软件开发和维护的重要标识,用于区分不同版本的 U-Boot,便于追踪问题和更新。
  • 代码

    VERSION = 2016
    PATCHLEVEL = 03
    SUBLEVEL =
    EXTRAVERSION =
    NAME =
    
  • 说明

    • VERSION:主版本号。
    • PATCHLEVEL:补丁版本号。
    • SUBLEVEL:次版本号。
    • EXTRAVERSION:附加版本信息。
    • NAME:版本名称。

MAKEFLAGS 变量

  • 作用:控制 Make 的行为。提高编译的可靠性,避免因隐含规则或路径问题导致的编译错误。

  • 代码

    MAKEFLAGS += -rR --include-dir=$(CURDIR)
    
  • 说明

    • -rR:禁止使用内置的隐含规则和变量定义。
    • --include-dir=$(CURDIR):指定搜索路径为当前目录。

命令输出

  • 作用:控制编译时命令的输出格式。方便开发者根据需要选择详细或简洁的输出。

  • 代码

    ifeq ("$(origin V)", "command line")KBUILD_VERBOSE = $(V)
    endif
    ifndef KBUILD_VERBOSEKBUILD_VERBOSE = 0
    endififeq ($(KBUILD_VERBOSE),1)quiet =Q =
    elsequiet=quiet_Q = @
    endif
    
  • 说明

    • V=1:启用完整命令输出。
    • V=0:启用短命令输出。

静默输出

  • 作用:编译时不输出任何命令信息。适用于不需要查看编译过程的场景。

  • 代码

    ifneq ($(filter s% -s%,$(MAKEFLAGS)),)quiet=silent_
    endif
    
  • 说明

    • 使用 make -s 启用静默输出。

编译结果输出目录

  • 作用:将编译生成的文件输出到指定目录。可以避免与源码文件混合。

  • 代码

    ifeq ("$(origin O)", "command line")KBUILD_OUTPUT := $(O)
    endif
    ifneq ($(KBUILD_OUTPUT),)$(shell mkdir -p $(KBUILD_OUTPUT))
    endif
    
  • 说明

    • 使用 make O=out 指定输出目录为 out

代码检查

  • 作用:检查代码是否符合规范。

  • 代码

    ifeq ("$(origin C)", "command line")KBUILD_CHECKSRC = $(C)
    endif
    ifndef KBUILD_CHECKSRCKBUILD_CHECKSRC = 0
    endif
    
  • 说明

    • make C=1:检查需要重新编译的文件。
    • make C=2:检查所有源码文件。

模块编译

  • 作用:单独编译某个模块。方便开发者快速测试和调试特定模块。

  • 代码

    ifdef SUBDIRSKBUILD_EXTMOD ?= $(SUBDIRS)
    endif
    ifeq ("$(origin M)", "command line")KBUILD_EXTMOD := $(M)
    endif
    
  • 说明

    • 使用 make M=dir 编译指定目录的模块。

获取主机架构和系统

  • 作用:获取当前主机的架构和操作系统信息。确保编译环境与目标环境一致,避免因主机环境与目标环境不匹配导致的编译错误。

  • 代码

    HOSTARCH := $(shell uname -m | \sed -e s/i.86/x86/ \-e s/sun4u/sparc64/ \-e s/arm.*/arm/ \-e s/sa110/arm/ \-e s/ppc64/powerpc/ \-e s/ppc/powerpc/ \-e s/macppc/powerpc/ \-e s/sh.*/sh/)HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \sed -e 's/\(cygwin\).*/cygwin/')export HOSTARCH HOSTOS
    
  • 说明

    • HOSTARCH:主机架构。
    • HOSTOS:主机操作系统。

设置目标架构和交叉编译器

  • 作用:设置目标板的架构和交叉编译器。确保编译出的 U-Boot 能够在目标板上运行。

  • 代码

    ifeq ($(HOSTARCH),$(ARCH))CROSS_COMPILE ?=
    endifKCONFIG_CONFIG ?= .config
    export KCONFIG_CONFIG
    
  • 说明

    • 可以在顶层 Makefile 中直接定义 ARCHCROSS_COMPILE,避免每次编译时手动指定。

调用 scripts/Kbuild.include

  • 作用:包含 scripts/Kbuild.include 文件,定义一些通用的变量和函数。

  • 代码

    scripts/Kbuild.include: ;
    include scripts/Kbuild.include
    

导出其他变量

  • 作用:导出编译过程中需要的变量。确保子 Makefile 能够正确使用这些变量。

  • 代码

    export ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR
    export AS LD CC CPP AR NM LDR STRIP OBJCOPY OBJDUMP
    export KBUILD_CPPFLAGS NOSTDINC_FLAGS UBOOTINCLUDE OBJCOPYFLAGS LDFLAGS
    export KBUILD_CFLAGS KBUILD_AFLAGS
    
  • 说明

    • 导出架构、工具链、编译选项等变量。

make xxx_defconfig 过程

make xxx_defconfig 是一个关键的步骤,它用于根据指定的配置文件生成 .config 文件。这个 .config 文件包含了 U-Boot 的配置选项,后续的编译过程会依赖这个文件

顶层Makefile初始化

在顶层 Makefile 中,首先会初始化一些变量,并检查目标是否为配置目标(如 xxx_defconfig)。以下是关键代码段的分析:

# 定义一些变量
version_h := include/generated/version_autogenerated.h
timestamp_h := include/generated/timestamp_autogenerated.h# 定义不需要 .config 的目标
no-dot-config-targets := clean clobber mrproper distclean \help %docs check% coccicheck \ubootversion backup# 初始化变量
config-targets := 0
mixed-targets := 0
dot-config := 1# 检查目标是否为不需要 .config 的目标
ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)dot-config := 0endif
endif# 检查目标是否为配置目标
ifeq ($(KBUILD_EXTMOD),)ifneq ($(filter config %config,$(MAKECMDGOALS)),)config-targets := 1ifneq ($(words $(MAKECMDGOALS)),1)mixed-targets := 1endifendif
endif
  • MAKECMDGOALS 是 Make 的一个环境变量,保存了用户指定的目标列表。例如,执行 make mx6ull_alientek_emmc_defconfig 时,MAKECMDGOALS 就是 mx6ull_alientek_emmc_defconfig
  • config-targetsmixed-targets 用于判断目标是否为配置目标,以及是否有多个目标混合在一起。
  • mixed-targets:如果命令行中指定了多个目标(如 make oldconfig all),则 mixed-targets 被设置为 1。
  • dot-config:如果目标是配置目标(如 xxx_defconfig),则 dot-config 被设置为 1,表示需要包含 .config 文件。

处理配置目标

如果目标是配置目标(如 xxx_defconfig),Makefile 会执行以下代码:

ifeq ($(mixed-targets),1)# 如果有混合目标,逐个处理PHONY += $(MAKECMDGOALS) __build_one_by_one$(filter-out __build_one_by_one, $(MAKECMDGOALS)): __build_one_by_one__build_one_by_one:$(Q)set -e; \for i in $(MAKECMDGOALS); do \$(MAKE) -f $(srctree)/Makefile $$i; \done
elseifeq ($(config-targets),1)# 处理配置目标KBUILD_DEFCONFIG := sandbox_defconfigexport KBUILD_DEFCONFIG KBUILD_KCONFIGconfig: scripts_basic outputmakefile FORCE$(Q)$(MAKE) $(build)=scripts/kconfig $@%config: scripts_basic outputmakefile FORCE$(Q)$(MAKE) $(build)=scripts/kconfig $@endif
endif
  • %config 目标:这是一个通配符目标,匹配所有以 _config_defconfig 结尾的目标。例如,mx6ull_alientek_emmc_defconfig 就会匹配到这个目标。
  • 依赖项
    • scripts_basic:编译一些基本的工具,如 fixdep
    • outputmakefile:生成输出目录中的 Makefile(通常不会执行)。
    • FORCE:这是一个伪目标,总是会被重新生成,确保 %config 目标的命令每次都会执行。

依赖项处理

scripts_basic

scripts_basic 目标的作用是编译一些基本的工具,如 fixdep

关键代码片段:

scripts_basic:$(Q)$(MAKE) $(build)=scripts/basic$(Q)rm -f .tmp_quiet_recordmcount

分析

make -f ./scripts/Makefile.build obj=scripts/basic

这个命令会调用 scripts/Makefile.build,编译 scripts/basic 目录中的目标,生成 fixdep 工具。

outputmakefile

outputmakefile 目标的作用是生成输出目录中的 Makefile,但在大多数情况下不会执行。

关键代码片段:

outputmakefile:ifneq ($(KBUILD_SRC),)$(Q)ln -fsn $(srctree) source$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \$(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)endif

分析:

条件判断:如果 KBUILD_SRC 为空,则 outputmakefile 不会执行。

FORCE

FORCE 是一个伪目标,总是会被重新生成,确保 %config 目标的命令每次都会执行。

关键代码片段:

PHONY += FORCE
FORCE:

调用 scripts/Makefile.build

cripts_basic 的处理

scripts_basic 目标的命令会调用 scripts/Makefile.build,编译 scripts/basic 目录中的目标。

关键代码片段:

__build: $(if $(KBUILD_BUILTIN), $(builtin-target) $(lib-target) $(extra-y)) \$(if $(KBUILD_MODULES), $(obj-m) $(modorder-target)) \$(subdir-ym) $(always)@:

分析:

  1. 默认目标__build 是默认目标,依赖于 builtin-targetlib-targetextra-y 等变量。
  2. 生成 fixdep:最终会编译生成 scripts/basic/fixdep 工具。

%config 的处理

%config 目标的命令会调用 scripts/Makefile.build,处理 scripts/kconfig 目录中的目标。

关键代码片段:

%_defconfig: $(obj)/conf$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)

分析:

  1. 依赖项$(obj)/conf,即 scripts/kconfig/conf 工具。

  2. 命令

    scripts/kconfig/conf --defconfig=arch/../configs/xxx_defconfig Kconfig
    

    这个命令会使用 conf 工具,将 xxx_defconfig 文件中的配置输出到 .config 文件中。

总结

当执行 make xxx_defconfig 时,Makefile 会执行以下命令:

@make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig

这个命令会调用 scripts/Makefile.build,并传递 obj=scripts/kconfigxxx_defconfig 作为参数。

生成 .config 文件

scripts/kconfig/Makefile 中,有以下规则:

%_defconfig: $(obj)/conf$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
  • $(obj)/conf 是一个主机工具,用于解析 Kconfig 文件并生成 .config 文件。
  • --defconfig=arch/$(SRCARCH)/configs/$@ 指定了要使用的配置文件路径。
  • $(Kconfig) 是顶层 Kconfig 文件,用于描述 U-Boot 的配置选项。

最终,scripts/kconfig/conf 工具会根据 xxx_defconfig 文件和 Kconfig 文件生成 .config 文件。

make 命令全过程解析

概述

在配置好 U-Boot 后(通过 make xxx_defconfig 生成 .config 文件),可以直接运行 make 命令来编译 U-Boot。make 命令的默认目标是 _all,而 _all 依赖于 allall 又依赖于 ALL-y,最终生成 U-Boot 的二进制文件 u-boot.bin 和其他相关文件。


默认目标 _all

在顶层 Makefile 中,默认目标是 _all

关键代码片段:

# That's our default target when none is given on the command line
PHONY := _all
_all:

分析:

  1. _all 目标:这是 make 命令的默认目标。
  2. 依赖项_all 依赖于 all

目标 all 的依赖

all 目标依赖于 ALL-yALL-y 是一个变量,包含了需要生成的所有文件。

关键代码片段:

all: $(ALL-y)

ALL-y 的定义:

ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check
ALL-$(CONFIG_ONENAND_U_BOOT) += u-boot-onenand.bin
ALL-$(CONFIG_SPL) += spl/u-boot-spl.bin
ALL-$(CONFIG_TPL) += tpl/u-boot-tpl.bin
ALL-$(CONFIG_OF_SEPARATE) += u-boot.dtb
ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf

分析:

  1. ALL-y:包含了 U-Boot 的主要输出文件,如 u-boot.binu-boot.srec 等。
  2. 条件依赖:根据配置选项(如 CONFIG_ONENAND_U_BOOT),ALL-y 可能会包含其他文件。

生成 u-boot.bin

u-boot.bin 是 U-Boot 的最终二进制文件,其生成过程涉及多个步骤。

u-boot.bin 的依赖

u-boot.bin 依赖于 u-boot-nodtb.bin

关键代码片段:

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

分析:

  1. if_changed 函数:用于检查依赖文件是否有更新,如果有更新则执行命令。
  2. 命令:将 u-boot-nodtb.bin 复制为 u-boot.bin

u-boot-nodtb.bin 的依赖

u-boot-nodtb.bin 依赖于 u-boot

关键代码片段:

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

分析:

  1. if_changed 函数:检查 u-boot 是否有更新,如果有更新则执行 objcopy 命令。
  2. objcopy 命令:将 u-boot 转换为 u-boot-nodtb.bin

u-boot 的依赖

u-boot 依赖于 u-boot-initu-boot-mainu-boot.lds

关键代码片段:

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

u-boot-initu-boot-main 的定义:

u-boot-init := $(head-y)
u-boot-main := $(libs-y)

分析:

  1. u-boot-init:通常是 CPU 架构相关的启动文件,如 arch/arm/cpu/armv7/start.o
  2. u-boot-main:是所有子目录中 built-in.o 文件的集合。
  3. u-boot.lds:是链接脚本,用于指定链接顺序和内存布局。

链接过程

u-boot 的生成是通过链接 u-boot-initu-boot-main 中的目标文件完成的。

关键代码片段:

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

链接命令:

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/cpu/armv7/built-in.o \arch/arm/imx-common/built-in.o \arch/arm/lib/built-in.o \board/freescale/common/built-in.o \board/freescale/mx6ull_alientek_emmc/built-in.o \cmd/built-in.o \common/built-in.o \disk/built-in.o \drivers/built-in.o \drivers/dma/built-in.o \drivers/gpio/built-in.o \... \--end-group \arch/arm/lib/eabi_compat.o \-lgcc -Map u-boot.map

分析:

  1. 链接脚本 u-boot.lds:指定了链接顺序和内存布局。
  2. start.o:是 CPU 的启动文件,通常是第一个被执行的代码。
  3. built-in.o:是各个子目录中的目标文件集合,包含了 U-Boot 的所有功能模块。

总结

make 命令的执行流程可以总结为以下几个步骤:

  1. 默认目标 _allmake 命令的默认目标是 _all,它依赖于 all
  2. 目标 allall 依赖于 ALL-yALL-y 包含了需要生成的所有文件,如 u-boot.bin
  3. 生成 u-boot.bin
    • u-boot.bin 依赖于 u-boot-nodtb.bin
    • u-boot-nodtb.bin 依赖于 u-boot
    • u-boot 依赖于 u-boot-initu-boot-mainu-boot.lds
  4. 链接过程:通过链接 u-boot-initu-boot-main 中的目标文件,生成 u-boot
  5. 最终文件:生成 u-boot.bin 和其他相关文件

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词