【u-boot-2018.05】make配置过程分析
https://blog.csdn.net/q_z_r_s/article/details/80718518
从u-boot-2014.10版本引入Kbuild系统之后,Makefile的管理和组织跟以前版本的代码有了很大的不同,这使Makefile变得更加复杂。整个Makefile中,include很多其它不同用途的Makefile,各种目标和依赖也很多,因此要想搞清楚make的执行过程很困难;使用u-boot之前首先是对其进行配置,命令为:
make xxx_defconfig
上述命令执行之后会生成对应的.config文件,接下来就可以进行最后的编译工作了,直接输入make即可。
配置流程分析
执行make xxx_defconfig命令时,u-boot根目录下的Makefile中有唯一的规则匹配目标:
%config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
其中$(build)在kbuild.include中定义:
build := -f $(srctree)/scripts/Makefile.build obj
依赖scripts_basic:
# Basic helpers built in scripts/
PHONY += scripts_basic
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
$(Q)rm -f .tmp_quiet_recordmcount
可见scripts_basic没有进一步的依赖,展开后规则如下:
scripts_basic:
$(Q) make -f ./scripts/Makefile.build obj=scripts/basic
$(Q) rm -f .tmp_quiet_recordmcount
简而言之,scripts_basic规则
scripts_basic:
$(Q) make -f ./scripts/Makefile.build obj=scripts/basic
的最终结果就是编译scripts/basic/fixdep.c生成主机上的可执行文件fixdep。
第二次调用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)
这里替换展开后相当于:
include ./scripts/kconfig/Makefile
对于这里传入的xxx_defconfig,匹配的目标是:
%_defconfig: $(obj)/conf
$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
展开为:
xxx_defconfig: scripts/kconfig/conf
$(Q)scripts/kconfig/conf --defconfig=arch/../configs/xxx_defconfig Kconfig
此处目标xxx_defconfig依赖于scripts/kconfig/conf,接下来检查并生成依赖。
hostprogs-y := conf nconf mconf kxgettext qconf gconf
hostprogs-y指出conf被定义为主机上执行的程序,其依赖于另外两个文件:
conf-objs := conf.o zconf.tab.o
通过编译conf.c和zconf.tab.c生成conf-objs,并链接为scripts/kconfig/conf。
生成依赖后就是执行目标的命令了:
$(Q)scripts/kconfig/conf --defconfig=arch/../configs/xxx_defconfig Kconfig
conf工具从根目录下开始树状读取默认的Kconfig文件,分析其配置并保存在内存中。分析完默认的Kconfig后再读取指定文件(即arch/../configs/xxx_defconfig)更新得到最终的符号表,并输出到.config文件中。
u-boot-2016 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
实例执行配置命令
u-boot的编译跟kernel编译一样,分两步执行:
- 第一步:配置,执行make xxx_defconfig
进行各项配置,生成.config
文件
- 第二部:编译,执行make进行编译,生成可执行的二进制文件u-boot.bin或u-boot.elf
先从简单的make defconfig
配置过程着手吧。
命令行输入:
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
- $(</span>Q)<span class="hljs-variable">$(MAKE) $(</span>build)=scripts/kconfig <span class="hljs-variable">$@
对于目标,rpi_3_32b_defconfig
,展开则有:
- rpi_3_32b_defconfig: scripts_basic outputmakefile FORCE
- $(</span><span class="hljs-constant">Q</span>)<span class="hljs-variable">$(MAKE) $(</span>build)=scripts/kconfig rpi_3_32b_defconfig</div></div></li></ol></code><ul class="pre-numbering" style="opacity: 0;"><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li></ul><div class="hljs-button" data-title="复制"></div></pre><ul class="pre-numbering" style="opacity:0;"><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li></ul><div class="save_code tracking-ad" style="display:none;"><a target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets_01.png" alt="save_snippets_01.png"></a></div><ul class="pre-numbering"><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li></ul><p>其中<code>$(build)在
kbuild.include
中定义:build := -f $(srctree)/scripts/Makefile.build obj
i. 依赖scripts_basic
依赖scripts_basic:
- # Basic helpers built in scripts/
- PHONY += scripts_basic
- scripts_basic:
- $(</span><span class="hljs-constant">Q</span>)<span class="hljs-variable">$(MAKE) $(</span>build)=scripts/basic</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-variable">$(Q)rm -f .tmp_quiet_recordmcount
可见scripts_basic没有进一步的依赖,展开后规则如下:
- scripts_basic:
- $(Q) make -f ./scripts/Makefile<span class="hljs-preprocessor">.build</span> obj=scripts/basic</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> $(Q) rm -f .tmp_quiet_recordmcount
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 ($(</span>KBUILD_SRC),)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-variable">$(Q)ln -fsn $(</span>srctree) <span class="hljs-keyword">source</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-variable">$(Q)$(</span>CONFIG_SHELL) <span class="hljs-variable">$(srctree)/scripts/mkmakefile \
- $(</span>srctree) <span class="hljs-variable">$(objtree) $(</span>VERSION) <span class="hljs-variable">$(PATCHLEVEL)
- endif
outputmakefile也没有进一步的依赖。
如果执行如下命令:make rpi_3_32b_defconfig O=out
那么所有生成的目标都将放到out目录,此时会通过outputmakefile导出一个makefile到out目录进行编译。
由于在当前目录下编译,
$(KBUILD_SRC)
为空,不需要导出makefile文件,outputmakefile为空目标。
iii. 依赖FORCE
依赖FORCE:
- PHONY += FORCE
- FORCE:
FORCE
被定义为一个空目标。
如果一个目标添加FORCE
依赖,每次编译都会去先去执行FORCE
(实际上什么都不做),然后运行命令更新目标,这样就能确保目标每次都会被更新。在这里也就保证目标rpi_3_32b_defconfig
的命令:$(</span><span class="hljs-constant">Q</span>)<span class="hljs-variable">$(MAKE) $(build)=scripts/kconfig rpi_3_32b_defconfig
总是能够被执行。
以上是
rpi_3_32b_defconfig
的所有依赖,分析完依赖后再分析命令。
2. 顶层make defconfig的命令
i. 依赖scripts_basic的命令
目标
rpi_3_32b_defconfig
的三个依赖
scripts_basic
,outputmakefile
和FORCE
中,只有scripts_basic
需要执行命令,如下- scripts_basic:
- $(Q) make -f ./scripts/Makefile<span class="hljs-preprocessor">.build</span> obj=scripts/basic</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> $(Q) rm -f .tmp_quiet_recordmcount
然后Make命令会转到文件
scripts/Makefile.build
去执行。
第一次调用scripts/Makefile.build进行编译
文件script/Makefile.build
的开头会根据传入的
obj=scripts/basic
参数设置src=scripts/basic
:- prefix := tpl
- src := $(</span>patsubst <span class="hljs-variable">$(prefix)/%,%,$(</span>obj))</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">ifeq (<span class="hljs-variable">$(obj),$(</span>src))</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">prefix := spl</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">src := <span class="hljs-variable">$(patsubst $(</span>prefix)/<span class="hljs-variable">%,</span><span class="hljs-variable">%,</span><span class="hljs-variable">$(obj))
- ifeq ($(</span>obj),<span class="hljs-variable">$(src))
- prefix := .
- endif
- endif
然后搜寻
$(srctree)/$(src)
子目录下的makefile,并包含进来:
- # The filename Kbuild has precedence over Makefile
- kbuild-dir := $(</span><span class="hljs-keyword"><span class="hljs-keyword">if</span></span> <span class="hljs-variable">$(filter /%,$(</span>src)),<span class="hljs-variable">$(src),$(</span>srctree)/<span class="hljs-variable">$(src))
- kbuild-file := $(</span><span class="hljs-keyword"><span class="hljs-keyword">if</span></span> <span class="hljs-variable">$(wildcard $(</span>kbuild-dir)/Kbuild),<span class="hljs-variable">$(kbuild-dir)/Kbuild,$(</span>kbuild-dir)/Makefile)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">include</span> <span class="hljs-variable">$(kbuild-file)
这里展开替换后相当于:
include ./scripts/basic/Makefile
文件
scripts/basic/Makefile
中定义了编译在主机上执行的工具fixdep:
- hostprogs-y := fixdep
- always := $(</span>hostprogs-y)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment"><span class="hljs-comment"># fixdep is needed to compile other host programs</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-variable">$(addprefix $(</span>obj)/,<span class="hljs-variable">$(filter-out fixdep,$(</span>always)))<span class="hljs-symbol">:</span> <span class="hljs-variable">$(obj)/fixdep
工具fixdep用于更新每一个生成目标的依赖文件
*.cmd
。上面定义的这个
$(always)
在
scripts/Makefile.build
里会被添加到targets中:targets += $(extra-y)</span> <span class="hljs-variable">$(MAKECMDGOALS) $(always)
关于如何编译主机上可执行的程序,会在另外的文章中分析。
简而言之,
scripts_basic
规则
- scripts_basic:
- $(Q) make -f ./scripts/Makefile.build obj=scripts/basic
的最终结果就是编译
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
其中
$(build)
在
kbuild.include
中定义:- ###
- # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
- # Usage:
- # $(Q)$(MAKE) $(build)=dir</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">build <span class="hljs-symbol">:</span>= -f $(srctree)/scripts/Makefile.build obj
这个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 := $(</span><span class="hljs-keyword"><span class="hljs-keyword">if</span></span> <span class="hljs-variable">$(filter /%,$(</span>src)),<span class="hljs-variable">$(src),$(</span>srctree)/<span class="hljs-variable">$(src))
- kbuild-file := $(</span><span class="hljs-keyword"><span class="hljs-keyword">if</span></span> <span class="hljs-variable">$(wildcard $(</span>kbuild-dir)/Kbuild),<span class="hljs-variable">$(kbuild-dir)/Kbuild,$(</span>kbuild-dir)/Makefile)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">include</span> <span class="hljs-variable">$(kbuild-file)
这里替换展开后相当于:
include ./scripts/kconfig/Makefile
文件
scripts/kconfig/Makefile
中定义了所有匹配
%config
的目标:- PHONY += xconfig gconfig menuconfig config silentoldconfig update-po-config \
- localmodconfig localyesconfig
- PHONY += oldnoconfig savedefconfig defconfig
- PHONY += kvmconfig
- PHONY += tinyconfig
对于这里传入的
rpi_3_32b_defconfig
,匹配的目标是:
- %_defconfig: $(</span>obj)/conf</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-variable">$(Q)$<</span> <span class="hljs-variable">$(silent) --defconfig=arch/$(</span>SRCARCH)/configs/<span class="hljs-variable">$@ $(Kconfig)
展开为:
- rpi_3_32b_defconfig: scripts/kconfig/conf
- $(Q)scripts/kconfig/conf --defconfig=arch/../configs/rpi_3_32b_defconfig Kconfig
此处目标
rpi_3_32b_defconfig
依赖于
scripts/kconfig/conf
,接下来检查并生成依赖。hostprogs-y := conf nconf mconf kxgettext qconf gconf
hostprogs-y
指出conf被定义为主机上执行的程序,其依赖于另外两个文件:
conf-objs := conf.o zconf.tab.o
通过编译
conf.c
和
zconf.tab.c
生成conf-objs
,并链接为scripts/kconfig/conf
。生成依赖后就是执行目标的命令了:
$(Q)scripts/kconfig/conf --defconfig=arch/../configs/rpi_3_32b_defconfig Kconfig
工具
scripts/kconfig/conf
的操作会在单独的文章中分析,此处只做简要的说明:
conf
工具从根目录下开始树状读取默认的
Kconfig
文件,分析其配置并保存在内存中。分析完默认的Kconfig
后再读取指定文件(即arch/../configs/rpi_3_32b_defconfig
)更新得到最终的符号表,并输出到.config
文件中。至此完成了
make rpi_3_32b_defconfig
执行配置涉及的所有依赖和命令的分析。
make defconfig配置流程简图
整个配置流程阐述得比较啰嗦,可以用一个简单的依赖图表示,如下:
(可以将图片拖到浏览器的其他窗口看大图)
【u-boot-2018.05】make配置过程分析的更多相关文章
- Spring Boot之实现自动配置
GITHUB地址:https://github.com/zhangboqing/springboot-learning 一.Spring Boot自动配置原理 自动配置功能是由@SpringBootA ...
- 【spring boot】spring boot中使用定时任务配置
spring boot中使用定时任务配置 =============================================================================== ...
- 4、Spring Boot 2.x 自动配置原理
1.4 Spring Boot 自动配置原理 简介 spring boot自动配置功能可以根据不同情况来决定spring配置应该用哪个,不应该用哪个,举个例子: Spring的JdbcTemplate ...
- 黑马_13 Spring Boot:05.spring boot 整合其他技术
13 Spring Boot: 01.spring boot 介绍&&02.spring boot 入门 04.spring boot 配置文件 05.spring boot 整合其他 ...
- 学记:为spring boot写一个自动配置
spring boot遵循"约定优于配置"的原则,使用annotation对一些常规的配置项做默认配置,减少或不使用xml配置,让你的项目快速运行起来.spring boot的神奇 ...
- Spring Boot 探索系列 - 自动化配置篇
26. Logging Prev Part IV. Spring Boot features Next 26. Logging Spring Boot uses Commons Logging f ...
- Spring Boot 2.0 教程 | 配置 Undertow 容器
欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 资深架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 文章首发于个人网站 https://ww ...
- Microsoft Artificial Intelligence Conference(2018.05.21)
时间:2018.05.21地点:北京嘉丽大酒店
- Spring Boot实践——用外部配置填充Bean属性的几种方法
引用:https://blog.csdn.net/qq_17586821/article/details/79802320 spring boot允许我们把配置信息外部化.由此,我们就可以在不同的环境 ...
随机推荐
- 记录一下WPF中自寄宿asp.net服务添加urlacl的问题
asp.net公开服务地址时,由于当前用户权限问题,会导致服务地址未添加到urlacl池中报错. 关于添加urlacl的细节,请参考我之前的文章:asp.net self host and urlac ...
- Mac上的应用,例如Xcode需要输入原始下载账号才能更新问题
为了免下载安装Xcode,安装时使用了别人提供的Xcode.dmg安装,或者公司接管上任同事使用的Mac时,上面的应用都是用别人的账号购买下载的,而非使用自己账号在AppStore下载的. 这样的安装 ...
- eclipse下 hibernate逆向数据库操作示例!!
做项目必然要先进行数据库表设计,然后根据数据库设计建立实体类(VO),这是理所当然的,但是到公司里做项目后,让我认识到,没有说既进行完数据库设计后还要再“自己”建立一变VO.意思是,在项目设计时,要么 ...
- 2018.03.29 python-matplotlib 图表生成
'''Matplotlib -> 一个python版的matlab绘图接口,以2D为主,支持python,numpy,pandas基本数据结构,高效图标库''' import numpy as ...
- 几家大的券商的PB系统以及算法交易概况大致是怎样的?
PB的定位是托管-清算-交易.目前的PB系统方面的竞争点主要放在了交易环节(毕竟托管和清算没有多大的差异).目前的pb交易环节的技术提供有恒生.讯投.金证.同花顺等,以满足私募及高净值个人多样化交易和 ...
- 应用安全 - 工具 - 知道创宇 - CEYE检测平台
DNS Query
- 应用安全 - CMS - PHPCMS漏洞汇总
CVE-2011-0644 Date: 2011.1 类型: /flash_upload.php SQL注入 影响版本:phpCMS 2008 V2 PHPCMS PHPCMS通杀XSS 在我要报错功 ...
- 【QT开发】QT在windows下的exe应用程序如何在别人的电脑上直接运行
当你利用QT编译了一个可执行程序,需要将这个可执行程序拷贝到别人的电脑上运行,这个时候除了这个可执行程序外,还需要支持的库才可用运行.一般来说通过下面的方法可以实现. 首先,需要看你用的是什 ...
- k8s/01开启云原生之门(Mooc)
一.kubernetes(k8s)基础知识 1.简介 在2017年Kubernetes战胜了两个强大的竞争对手Swarm和Mesos,成为容器管理与调度编排领域的首选平台和事实标准. 2014年k8s ...
- vue仿阿里云后台管理(附加阿里巴巴图标使用)
先看下页面截图,在线演示地址http://aliadmin.zengjielin.top 下面有开源的代码 页面分成三大部分头部,头部菜单栏,侧边菜单栏,右侧内容栏. 现在我们担心的是怎么使用侧边栏. ...