二、编译第一步 make xxx_defconfig
3.1 顶层make defconfig规则
make xxx_defconfig 的执行主要分成三个部分:
- 执行
make -f ./scripts/Makefile.build obj=scripts/basic,编译生成scripts/basic/fixdep工具 - 执行
make -f ./scripts/Makefile.build obj=scripts/kconfig rpi_3_32b_defconfig编译生成scripts/kconfig/conf工具 - 执行
scripts/kconfig/conf --defconfig=arch/../configs/xxx_defconfig Kconfig生成最终的.config配置文件
执行 make xxx_defconfig 命令时,u-boot 根目录下的 Makefile 中有唯一的规则匹配目标:
代码第 467 到 478 行
# ===========================================================================
# *config targets only - make sure prerequisites are updated, and descend
# in scripts/kconfig to make the *config target KBUILD_DEFCONFIG := sandbox_defconfig
export KBUILD_DEFCONFIG KBUILD_KCONFIG config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@ %config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
注释意思为,仅限 *config 目标,确保先决条件已经更新,并在 scripts/kconfig 下创建 *config 目标。上面有两个变量 config 和 %config,% 符号为通配符,对应所有的 xxxconfig 目标,前面已经说过。我们的 make xxx_defconfig 就对应 %config,我们并没有执行 make config 命令。
Makefile中几种变量赋值运算符:
- = :最简单的赋值
- := :一般也是赋值
- 以上这两个大部分情况下效果是一样的,但是有时候不一样。
- 用 = 赋值的变量,在被解析时他的值取决于最后一次赋值时的值,所以看变量引用的值时不能只往前面看,还要往后面看。
- 用 := 来赋值的,则是就地直接解析,只用往前看即可。
- ?= : 如果变量前面并没有赋值过则执行这条赋值,如果前面已经赋值过了则本行被忽略。
- += 用来给一个已经赋值的变量接续赋值,意思就是把这次的值加到原来的值的后面,有点类似于strcat
- 在shell makefile等文件中,可以认为所有变量都是字符串,+= 就相当于给字符串 strcat 接续内容
- +=续接的内容和原来的内容之间会自动加一个空格隔开
3.1.1 代码执行到%config 的条件
先往上分析下这段代码的执行条件: ifeq ($(config-targets),1),代码在415 到 447 行
1 # To make sure we do not include .config for any of the *config targets
2 # catch them early, and hand them over to scripts/kconfig/Makefile
3 # It is allowed to specify more targets when calling make, including
4 # mixing *config targets and build targets.
5 # For example 'make oldconfig all'.
6 # Detect when mixed targets is specified, and make a second invocation
7 # of make so .config is not included in this case either (for *config).
8
9 version_h := include/generated/version_autogenerated.h
10 timestamp_h := include/generated/timestamp_autogenerated.h
11
12 no-dot-config-targets := clean clobber mrproper distclean \
13 help %docs check% coccicheck \
14 ubootversion backup tests
15
16 config-targets := 0
17 mixed-targets := 0
18 dot-config := 1
19
20 ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
21 ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
22 dot-config := 0
23 endif
24 endif
25
26 ifeq ($(KBUILD_EXTMOD),)
27 ifneq ($(filter config %config,$(MAKECMDGOALS)),)
28 config-targets := 1
29 ifneq ($(words $(MAKECMDGOALS)),1)
30 mixed-targets := 1
31 endif
32 endif
33 endif
代码注释内容:为了确保我们不包含任何 * config 目标的 .config,请尽早捕获它们,并将它们交给 scripts / kconfig / Makefile。调用make 时允许指定更多目标,包括混合 * config 目标和构建目标。例如 'make oldconfig all' 。检测何时指定了混合目标,并进行make的第二次调用,因此 .config不包含在这种情况下(对于* config)。
- version_h:版本号文件,此文件是自动生成的
- timestamp_h:时间戳文件,此文件是自动生成的
- no-dot-config-targets:指代的是那些和 .config 没有关系的目标
- config-targets:配置目标,初始值设置为0
- mixed-targets:混合目标,初始值设置为0
- dot-config:初始值设置为1
变量 MAKECMDGOALS:make 在执行时会设置一个特殊变量 -- "MAKECMDGOALS" ,该变量记录了命令行参数指定的终极目标列表,没有通过参数指定终极目标时此变量为空。该变量仅限于用在特殊场合(比如判断),在 Makefile 中最好不要对它进行重新定义。
我们执行 make xxx_defconfig 的时候,MAKECMDGOALS 变量的值就为 xxx_defconfig。
filter 函数 和 filter-out 函数:
1 $(filter PATTERN…,TEXT)
2 函数名称: 过滤函数— filter。
3 函数功能: 过滤掉字串“ TEXT”中所有不符合模式“ PATTERN”的单词,保留所
4 有符合此模式的单词。可以使用多个模式。模式中一般需要包含模式字
5 符“ %”。存在多个模式时,模式表达式之间使用空格分割。
6 返回值:空格分割的“ TEXT”字串中所有符合模式“ PATTERN”的字串。
7 函数说明:“ filter”函数可以用来去除一个变量中的某些字符串
1 $(filter-out PATTERN...,TEXT)
2 函数名称: 反过滤函数— filter-out
3 函数功能: 和“ filter”函数实现的功能相反。过滤掉字串“ TEXT”中所有符合模式“ PATTERN”的单词,保留所有不符合此模式的单词。
可以有多个模式。存在多个模式时,模式表达式之间使用空格分割
4 返回值: 空格分割的“ TEXT”字串中所有不符合模式“ PATTERN”的字串。
5 函数说明: “ filter-out”函数也可以用来去除一个变量中的某些字符串,(实现和“ filter”函数相反)
代码执行的过程就为,如果 过滤掉 MAKECMDGOALS 不符合 no-dot-config-targets 后结果不为空,则执行分支语句。很显然过滤后为空,则不执行分支语句,dot-config 依然 值为1。
接着执行下一条 ifeq 语句,对 KBUILD_EXTMOD 进行判定。KBUILD_EXTMODE 的赋值地方在代码 182 到 191 行处:
# Use make M=dir to specify directory of external module to build
# Old syntax make ... SUBDIRS=$PWD is still supported
# Setting the environment variable KBUILD_EXTMOD take precedence
ifdef SUBDIRS
KBUILD_EXTMOD ?= $(SUBDIRS)
endif ifeq ("$(origin M)", "command line")
KBUILD_EXTMOD := $(M)
endif
由注释可以知道,SUBDIRS 这个变量是通过执行 make 的时候传进来的,我们并没有执行此项,所以未定义SUBDIRS,第一个分支不会去走。第二个 if 语句为 ifeq 语句,这里使用 origin 函数。
origin 函数不是操作变量(即它的参数),它只是获取此变量(参数)相关的信息,告诉我们这个变量的出处(定义方式)。
那么 ifeq 语句可以理解为 如果make传入的命令行变量存在且是M,那么,变量KBUILD_EXTMOD变为变量M的值。
第一阶段中我们并没有传入 M 值,则 KBUILD_EXTMOD 值为空
继续回到此小节主代码处,当前执行 KBUILD_EXTMOD 的判定,此处满足 ifeq 条件,开始执行分支语句,分支语句同样是一个判断,首先过滤掉 MAKECMDGOALS 不符合 config 和 %config 模式的字符串,然后返回 xxx_defconfig ,xxx_defconfig 再与 空进行比较,if 语句为 ifneq ,很显然, filter 语句不为空,与空进行比较,满足 ifneq 执行语句。
此处将 config-targets 重新赋值为 1;赋值完后,进行 ifneq 条件判断,再次涉及 makefile 的函数——words。

显然我们的传入的单词数据为1,与1相等,则不执行分支,即 mixed-targets 不进行重新赋值,依然为0。
再代码进行到 ifeq ($(config-targets),1) 时候,先进行了 ifeq ($(mixed-targets),1)分支,如果 mixed-targets 则执行另一条分支,就不会再执行ifeq ($(config-targets),1) 了。我们这里执行的ifeq ($(mixed-targets),1) 的 else中的分支语句。
到此处,ifeq ($(config-targets),1) 是否会执行已经分析完毕。
当前我们已经知道的变量的值为:
- MAKECMDGOALS = xxx_defconfig
- KBUILD_EXTMOD =
- version_h := include/generated/version_autogenerated.h
- timestamp_h := include/generated/timestamp_autogenerated.h
- no-dot-config-targets := clean clobber mrproper distclean help %docs check% coccicheck ubootversion backup tests
- config-targets := 1
- mixed-targets := 0
- dot-config := 1
3.1.2 %config分析
ifeq ($(config-targets),1) 中也由else分支,我们从上面的小节可以知道,else 分支不会去执行。所以很多代码可以忽略了

从这里可以知道,此处此处选择语句一直执行到 1655 行,466~480 行才是我们需要分析的。
471 到 472 行
KBUILD_DEFCONFIG := sandbox_defconfig
export KBUILD_DEFCONFIG KBUILD_KCONFIG
这里定义了两个环境变量:
- KBUILD_DEFCONFIG = sandbox_defconfig
- KBUILD_KCONFIG 为空
继续执行474 到 475 行
config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
此处目标没有匹配,不会去执行
继续执行477 478 行
%config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
%config 依赖scripts_basic outputmakefile FORCE
(1)依赖 FORCE
FORCE 的定义在 1748 和 1749 行
PHONY += FORCE
FORCE:
FORCE被定义为一个空目标。如果一个目标添加 FORCE 依赖,每次编译都会去先去执行 FORCE(实际上什么都不做),然后运行命令更新目标,这样就能确保目标每次都会被更新。
(2)依赖 scripts_basic
392 - 402 行
# ===========================================================================
# Rules shared between *config targets and build targets # Basic helpers built in scripts/
PHONY += scripts_basic
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
$(Q)rm -f .tmp_quiet_recordmcount # To avoid any implicit rule to kick in, define an empty command.
scripts/basic/%: scripts_basic ;
Q = @,MAKE = make,build 变量的定义在 scripts/Kbuild.include 文件中
主Makefile 在327-329 行包含 scripts/Kbuild.include 文件
# We need some generic definitions (do not try to remake the file).
scripts/Kbuild.include: ;
include scripts/Kbuild.include
build 变量在 scripts/Kbuild.include 在177 - 181 行定义
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
# Usage:
# $(Q)$(MAKE) $(build)=dir
build := -f $(srctree)/scripts/Makefile.build obj
srctree 定义在主 Makefile 中202-212 行
ifeq ($(KBUILD_SRC),)
# building in the source tree
srctree := .
else
ifeq ($(KBUILD_SRC)/,$(dir $(CURDIR)))
# building in a subdirectory of the source tree
srctree := ..
else
srctree := $(KBUILD_SRC)
endif
endif
KBUILD_SRC (构建的源码目录) 在执行 make 命令的时候并没有传入,设为空,则srctree 为当前 uboot 源码的根目录
scripts/Kbuild.include 在177 - 181 行的展开为:build := -f ./scripts/Makefile.build obj
主 Makefile 中 scripts_basic 的展开为:
1 scripts_basic:
2 make -f ./scripts/Makefile.build obj=scripts/basic # 根据传入的 obj 参数显示的执行 ./scripts/Makefile.build 文件
3 rm -f .tmp_quiet_recordmcount
./scripts/Makefile.build 文件之后再分析。
(3)outputmakefile 依赖
404 - 413 行
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
KBUILD_SRC 为空,所以ifneq 中的语句不会执行。 outputmakefile 为空
重新回到 %config 处
%config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
依据前面的条件,展开表达式为:
1 make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
3.2 总结
3.2.1 变量
- MAKECMDGOALS = xxx_defconfig
- KBUILD_EXTMOD =
- version_h := include/generated/version_autogenerated.h
- timestamp_h := include/generated/timestamp_autogenerated.h
- no-dot-config-targets := clean clobber mrproper distclean help %docs check% coccicheck ubootversion backup tests
- config-targets := 1
- mixed-targets := 0
- dot-config := 1
- KBUILD_SRC =
- build := -f ./scripts/Makefile.build obj
3.2.2 环境变量
- KBUILD_DEFCONFIG := sandbox_defconfig
- KBUILD_KCONFIG =
3.2.3 需要进行分析的地方
(1)scripts_basic 目标执行的命令
make -f ./scripts/Makefile.build obj=scripts/basic
(2)%config 目标执行的命令
make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
二、编译第一步 make xxx_defconfig的更多相关文章
- 三、编译第一步 make xxx_defconfig——Makefile.build 脚本
3.1 上章分析回顾 3.1 上章分析出的参数 3.1.1 变量 MAKECMDGOALS = xxx_defconfig KBUILD_EXTMOD = version_h := include/g ...
- 第一讲 从头开始做一个web qq 机器人,第一步获取smart qq二维码
新手教程: 前言:最近在看了一下很久很久以前做的qq机器人失效了,最近也在换工作目前还在职,时间很挺宽裕的.就决定从新搞一个web qq机器人 PC的协议解析出来有点费时间以后再做. 准备工作: 编译 ...
- 【转】APUE学习1:迈出第一步,编译myls.c
原文网址:http://blog.csdn.net/sddzycnqjn/article/details/7252444 注:以下写作风格均学习自潘云登前辈 /******************** ...
- Hadoop Hive概念学习系列之Hive里的2维坐标系统(第一步定位行键 -> 第二步定位字段)(二十三)
HBase里的4维坐标系统(第一步定位行键 -> 第二步定位列簇 -> 第三步定位列修饰符 -> 第四步定位时间戳) HBase里的4维坐标系统(第一步定位行键 ...
- Theano2.1.2-基础知识之第一步:代数
来自:http://deeplearning.net/software/theano/tutorial/adding.html Baby Steps - Algebra 一.两个标量相加 在学习the ...
- Java 学习第一步-JDK安装和Java环境变量配置
Java学习第一步——JDK安装及Java环境变量配置 [原文] 2014-05-30 9:09 Java SE 阿超 9046 views Java作为当下很主流的编程语言,学习Java的朋 ...
- (大数据工程师学习路径)第一步 Linux 基础入门----文件系统操作与磁盘管理
介绍 本节的文件系统操作的内容十分简单,只会包含几个命令的几个参数的讲解,但掌握这些也将对你在学习后续其他内容的过程中有极大帮助. 因为本课程的定位为入门基础,尽快上手,故没有打算涉及太多理论内容,前 ...
- APP反编译第一课《如何找到核心代码》
相信很多人都应该会去接触APP反编译,本小七给大家带来入门级别套路,自己也在慢慢摸索学习,一起成长吧.第一步,反编译需要的工具有:一.java环境,其实这里你只要安装了burp就不用管这个的二.apk ...
- Ruby Rails学习中:Sass 和 Asset Pipeline,布局中的链接(Rails路由,具名路由),用户注册: 第一步
接上篇: 一.Sass 和 Asset Pipeline Rails 中最有用的功能之一是 Asset Pipeline, 它极大地简化了静态资源文件(CSS.JavaScript 和图像)的生成和管 ...
随机推荐
- Node url模块
const url = require("url");var u = "https://www.jd.com:443/ad/index?uname=qd";// ...
- 如何根据元素的className获取元素?
getElementsByClassName()是HTML5 新增的DOM API.IE8以下不支持 我们知道,原生的方法,是getElementById()和getElementsByTagName ...
- override overload reintroduce的区别(delphi)
1.override overload reintroduce的中文叫法是什么? override:覆盖:overload:重载:Reintroduce:重定义 2.在子类中override或ov ...
- c++ 为自定义类添加stl遍历器风格的遍历方式
为仿照stl的遍历风格,实现对自定义类型的遍历. 1. 需要遍历的基础结构: struct ConnectionPtr { int id_; int port_; string addr_; //st ...
- Spring的编程式事务和声明式事务
事务管理对于企业应用来说是至关重要的,当出现异常情况时,它也可以保证数据的一致性. Spring事务管理的两种方式 spring支持编程式事务管理和声明式事务管理两种方式. 编程式事务使用Transa ...
- 牛客国庆集训派对Day2 H 期望
小贝喜欢玩卡牌游戏.某个游戏体系中共有N种卡牌,其中M种是稀有的.小贝每次和电脑对决获胜之后都会有一个抽卡机会,这时系统会随机从N种卡中选择一张给小贝.普通卡可能多次出现,而稀有卡牌不会被重复抽到.小 ...
- MT【68】一边柯西一边舍弃
求$\sqrt{x-5}+\sqrt{24-3x}$的最值. 通常考试时会考你求最大值,常见的方式有三角代换,这里给如下做法: 证明:$\sqrt{x-5}+\sqrt{24-3x}=\sqrt{x- ...
- FFT/NTT总结+洛谷P3803 【模板】多项式乘法(FFT)(FFT/NTT)
前言 众所周知,这两个东西都是用来算多项式乘法的. 对于这种常人思维难以理解的东西,就少些理解,多背板子吧! 因此只总结一下思路和代码,什么概念和推式子就靠巨佬们吧 推荐自为风月马前卒巨佬的概念和定理 ...
- SharePoint 2013 APP 开发示例 (四)JQuery访问REST
这个示例里,我们将用JQuery AJAX去发送一个 REST请求,并查看返回结果.为了让我们更好地理解REST 接口,我们将添加一个输入框让用户可以指定REST的URL, 这将让我们尝试着用构造的U ...
- Windows Server 2008配置Network Load Balancing(服务群集)
最近配置SharePoint 2013 WFE 时,客户提到要让多台WFE能load balance,于是研究了下Network Load Balancing. 当把一台服务器 ...