u-boot-2016.09 make配置过程分析

概述

本文基于u-boot树莓派3代配置过程进行分析,环境如下:
编译环境:Ubuntu 14.04 LTS
编译工具:arm-Linux-gnueabi-gcc
代码版本:u-boot v2016.09
配置文件:rpi_3_32b_defconfig

u-boot自v2014.10版本开始引入KBuild系统,Makefile的管理和组织跟以前版本的代码有了很大的不同,其Makefile更加复杂。整个Makefile中,嵌套了很多其它不同用途的Makefile,各种目标和依赖也很多,make分析很容易陷进去,让人摸不着头脑。
本文涉及的配置命令:

make rpi_3_32b_defconfig
   
   
  • 1
  • 1

实例执行配置命令

u-boot的编译跟kernel编译一样,分两步执行:
- 第一步:配置,执行make xxx_defconfig进行各项配置,生成.config文件
- 第二部:编译,执行make进行编译,生成可执行的二进制文件u-boot.bin或u-boot.elf

先从简单的make defconfig配置过程着手吧。
命令行输入:

make rpi_3_32b_defconfig V=1
   
   
  • 1
  • 1

编译输出如下:
make rpi_3_32b_defconfig V=1的输出

配置命令参数说明:
- rpi_3_32b_defconfig 是树莓派3代32位编译的配置文件
- V=1 指示编译显示详细的输出。默认V=0,编译仅显示必要的简略信息

从输出的log看,make rpi_3_32b_defconfig的执行主要分为3个部分,见图上的标示:
- 1. 执行make -f ./scripts/Makefile.build obj=scripts/basic,编译生成scripts/basic/fixdep工具
- 2. 执行make -f ./scripts/Makefile.build obj=scripts/kconfig rpi_3_32b_defconfig编译生成scripts/kconfig/conf工具
- 3. 执行scripts/kconfig/conf --defconfig=arch/../configs/rpi_3_32b_defconfig Kconfig生成最终的.config配置文件

跟原始的代码相比,执行make rpi_3_32b_defconfig后文件夹内容的变化如下:
配置前后文件夹内容变化

被后续编译用到的文件是.config。

详细配置流程分析

言归正传,整个配置流程的目的就是为了生成.config文件,下面详细分析.config文件是如何一步一步生成的。

Makefile的核心是依赖和命令。对于每个目标,首先会检查依赖,如果依赖存在,则执行命令更新目标;如果依赖不存在,则会以依赖为目标,先生成依赖,待依赖生成后,再执行命令生成目标。

1. 顶层make defconfig规则

执行make xxx_defconfig命令时,u-boot根目录下的Makefile中有唯一的规则匹配目标:

%config: scripts_basic outputmakefile FORCE
    $(Q)$(MAKE) $(build)=scripts/kconfig $@

   
   
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

对于目标,rpi_3_32b_defconfig,展开则有:

rpi_3_32b_defconfig: scripts_basic outputmakefile FORCE
    $(Q)$(MAKE) $(build)=scripts/kconfig rpi_3_32b_defconfig
   
   
  • 1
  • 2
  • 1
  • 2

其中$(build)kbuild.include中定义:

build := -f $(srctree)/scripts/Makefile.build obj
   
   
  • 1
  • 1
i. 依赖scripts_basic

依赖scripts_basic:

# Basic helpers built in scripts/
PHONY += scripts_basic
scripts_basic:
    $(Q)$(MAKE) $(build)=scripts/basic
    $(Q)rm -f .tmp_quiet_recordmcount

   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

可见scripts_basic没有进一步的依赖,展开后规则如下:

scripts_basic:
    $(Q) make -f ./scripts/Makefile.build obj=scripts/basic
    $(Q) rm -f .tmp_quiet_recordmcount
   
   
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
ii. 依赖outputmakefile

依赖outputmakefile:

PHONY += outputmakefile
# outputmakefile generates a Makefile in the output directory, if using a
# separate output directory. This allows convenient use of make in the
# output directory.
outputmakefile:
ifneq ($(KBUILD_SRC),)
    $(Q)ln -fsn $(srctree) source
    $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \
        $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
endif

   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

outputmakefile也没有进一步的依赖。
如果执行如下命令:

make rpi_3_32b_defconfig O=out
   
   
  • 1
  • 1

那么所有生成的目标都将放到out目录,此时会通过outputmakefile导出一个makefile到out目录进行编译。

由于在当前目录下编译,$(KBUILD_SRC)为空,不需要导出makefile文件,outputmakefile为空目标。

iii. 依赖FORCE

依赖FORCE:

PHONY += FORCE
FORCE:

   
   
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

FORCE被定义为一个空目标。
如果一个目标添加FORCE依赖,每次编译都会去先去执行FORCE(实际上什么都不做),然后运行命令更新目标,这样就能确保目标每次都会被更新。在这里也就保证目标rpi_3_32b_defconfig的命令:

$(Q)$(MAKE) $(build)=scripts/kconfig rpi_3_32b_defconfig
   
   
  • 1
  • 1

总是能够被执行。

以上是rpi_3_32b_defconfig的所有依赖,分析完依赖后再分析命令。

2. 顶层make defconfig的命令

i. 依赖scripts_basic的命令

目标rpi_3_32b_defconfig的三个依赖scripts_basicoutputmakefileFORCE中,只有scripts_basic需要执行命令,如下

scripts_basic:
    $(Q) make -f ./scripts/Makefile.build obj=scripts/basic
    $(Q) rm -f .tmp_quiet_recordmcount
   
   
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

然后Make命令会转到文件scripts/Makefile.build去执行。

第一次调用scripts/Makefile.build进行编译
文件script/Makefile.build的开头会根据传入的obj=scripts/basic参数设置src=scripts/basic:

prefix := tpl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := spl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := .
endif
endif
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

然后搜寻$(srctree)/$(src)子目录下的makefile,并包含进来:

# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)
   
   
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

这里展开替换后相当于:

include ./scripts/basic/Makefile
   
   
  • 1
  • 1

文件scripts/basic/Makefile中定义了编译在主机上执行的工具fixdep:

hostprogs-y := fixdep
always      := $(hostprogs-y)

# fixdep is needed to compile other host programs
$(addprefix $(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

工具fixdep用于更新每一个生成目标的依赖文件*.cmd

上面定义的这个$(always)scripts/Makefile.build里会被添加到targets中:

targets += $(extra-y) $(MAKECMDGOALS) $(always)
   
   
  • 1
  • 1

关于如何编译主机上可执行的程序,会在另外的文章中分析。

简而言之,scripts_basic规则

scripts_basic:
    $(Q) make -f ./scripts/Makefile.build obj=scripts/basic
   
   
  • 1
  • 2
  • 1
  • 2

的最终结果就是编译scripts/basic/fixdep.c生成主机上的可执行文件fixdep。至于为什么要编译fixdep和如何使用fixdep,会在另外的文章中分析。

ii. 顶层rpi_3_32b_defconfig的命令

完成对依赖scripts_basic的更新后,接下来就是执行顶层目标的命令完成对rpi_3_32b_defconfig的更新,展开后的规则如下:

rpi_3_32b_defconfig: scripts_basic outputmakefile FORCE
    make -f ./scripts/Makefile.build obj= scripts/kconfig rpi_3_32b_defconfig
   
   
  • 1
  • 2
  • 1
  • 2

其中$(build)kbuild.include中定义:

###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
# Usage:
# $(Q)$(MAKE) $(build)=dir
build := -f $(srctree)/scripts/Makefile.build obj
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

这个make命令会第二次转到scripts/Makefile.build去执行。

第二次调用scripts/Makefile.build进行编译
文件script/Makefile.build的开头会根据传入的obj=scripts/kconfig参数设置src=scripts/kconfig。然后搜寻$(srctree)/$(src)子目录下的makefile,由于src=scripts/kconfig参数不同于第一次调用的参数(src=scripts/basic),此处包含的makefile也不同于第一次的makefile了:

# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)
   
   
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

这里替换展开后相当于:

include ./scripts/kconfig/Makefile
   
   
  • 1
  • 1

文件scripts/kconfig/Makefile中定义了所有匹配%config的目标:

PHONY += xconfig gconfig menuconfig config silentoldconfig update-po-config \
    localmodconfig localyesconfig

PHONY += oldnoconfig savedefconfig defconfig

PHONY += kvmconfig

PHONY += tinyconfig

   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

对于这里传入的rpi_3_32b_defconfig,匹配的目标是:

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

展开为:

rpi_3_32b_defconfig: scripts/kconfig/conf
    $(Q)scripts/kconfig/conf  --defconfig=arch/../configs/rpi_3_32b_defconfig Kconfig

   
   
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

此处目标rpi_3_32b_defconfig依赖于scripts/kconfig/conf,接下来检查并生成依赖。

hostprogs-y := conf nconf mconf kxgettext qconf gconf
   
   
  • 1
  • 1

hostprogs-y指出conf被定义为主机上执行的程序,其依赖于另外两个文件:

conf-objs   := conf.o  zconf.tab.o
   
   
  • 1
  • 1

通过编译conf.czconf.tab.c生成conf-objs,并链接为scripts/kconfig/conf

生成依赖后就是执行目标的命令了:

$(Q)scripts/kconfig/conf  --defconfig=arch/../configs/rpi_3_32b_defconfig Kconfig
   
   
  • 1
  • 1

工具scripts/kconfig/conf的操作会在单独的文章中分析,此处只做简要的说明:

conf工具从根目录下开始树状读取默认的Kconfig文件,分析其配置并保存在内存中。分析完默认的Kconfig后再读取指定文件(即arch/../configs/rpi_3_32b_defconfig)更新得到最终的符号表,并输出到.config文件中。

至此完成了make rpi_3_32b_defconfig执行配置涉及的所有依赖和命令的分析。

make defconfig配置流程简图

整个配置流程阐述得比较啰嗦,可以用一个简单的依赖图表示,如下:
make defconfig配置中的依赖和命令
(可以将图片拖到浏览器的其他窗口看大图)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
u-boot-2016.11.tar.bz2是一个开源软件项目的压缩文件。该压缩文件是u-boot引导加载程序的源代码和相关文件的打包形式。u-boot(Universal Bootloader)是一款用于嵌入式系统的开源引导加载程序,用于初始化硬件并启动操作系统。 u-boot-2016.11.tar.bz2文件的扩展名.tar.bz2表示它是使用tar和bzip2两种工具进行压缩的。.tar是一个常用的文件打包工具,它可以将多个文件和目录打包成一个文件。.bz2是一个压缩工具,可以将文件进行高效压缩。 要使用u-boot-2016.11.tar.bz2文件,首先需要将其解压缩。可以使用tar命令进行解压缩,命令为tar -xjf u-boot-2016.11.tar.bz2。这将解压缩文件,并将源代码和其他相关文件提取到当前目录下。 解压缩后,可以在提取出的文件中找到u-boot引导加载程序的源代码和相关文件。可以根据需要进行定制和编译,生成适合特定硬件平台的引导加载程序。u-boot支持多种处理器架构和开发板,可以根据需要进行配置。 根据u-boot-2016.11.tar.bz2文件的版本号来看,它是2016年11月发布的版本。这意味着该版本已经存在一段时间,并可能具有稳定性和经过验证的特性。对于需要使用u-boot的开发者和嵌入式系统制造商,这个版本可以作为一个可靠的基础进行开发和定制。 总之,u-boot-2016.11.tar.bz2是u-boot引导加载程序的源代码和相关文件的压缩包。解压缩后,可以通过定制和编译源代码,生成适合特定硬件平台的引导加载程序。这个版本已经存在一段时间,并可能具有可靠的特性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值