上一章中,对Makefile相关源码进行了初步分析,这里结合编译过程具体分析其执行过程。
nanopi_neo2_defconfig
文件位于./config/
目录下,内容如下
CONFIG_ARM=y
CONFIG_ARCH_SUNXI=y
CONFIG_MACH_SUN50I_H5=y
CONFIG_DRAM_CLK=672
CONFIG_DRAM_ZQ=3881977
CONFIG_DEFAULT_DEVICE_TREE="sun50i-h5-nanopi-neo2"
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SPL=y
# CONFIG_CMD_FLASH is not set
# CONFIG_CMD_FPGA is not set
# CONFIG_SPL_DOS_PARTITION is not set
# CONFIG_SPL_ISO_PARTITION is not set
# CONFIG_SPL_EFI_PARTITION is not set
CONFIG_SUN8I_EMAC=y
CONFIG_USB_EHCI_HCD=y
CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE=y
首先通过make nanopi_neo2_defconfig -n
命令,-n
表示仅输出执行过程中的命令序列,而不真正执行
make -f ./scripts/Makefile.build obj=scripts/basic
set -e; echo ' HOSTCC scripts/basic/fixdep'; cc -Wp,-MD,scripts/basic/.fixdep.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -o scripts/basic/fixdep scripts/basic/fixdep.c ; scripts/basic/fixdep scripts/basic/.fixdep.d scripts/basic/fixdep 'cc -Wp,-MD,scripts/basic/.fixdep.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -o scripts/basic/fixdep scripts/basic/fixdep.c ' > scripts/basic/.fixdep.tmp; rm -f scripts/basic/.fixdep.d; mv -f scripts/basic/.fixdep.tmp scripts/basic/.fixdep.cmd
:
rm -f .tmp_quiet_recordmcount
make -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfig
set -e; echo ' HOSTCC scripts/kconfig/conf.o'; cc -Wp,-MD,scripts/kconfig/.conf.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DCURSES_LOC="" -DNCURSES_WIDECHAR=1 -DLOCALE -c -o scripts/kconfig/conf.o scripts/kconfig/conf.c; scripts/basic/fixdep scripts/kconfig/.conf.o.d scripts/kconfig/conf.o 'cc -Wp,-MD,scripts/kconfig/.conf.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DCURSES_LOC="" -DNCURSES_WIDECHAR=1 -DLOCALE -c -o scripts/kconfig/conf.o scripts/kconfig/conf.c' > scripts/kconfig/.conf.o.tmp; rm -f scripts/kconfig/.conf.o.d; mv -f scripts/kconfig/.conf.o.tmp scripts/kconfig/.conf.o.cmd
echo ' SHIPPED scripts/kconfig/zconf.tab.c'; cat scripts/kconfig/zconf.tab.c_shipped > scripts/kconfig/zconf.tab.c
echo ' SHIPPED scripts/kconfig/zconf.lex.c'; cat scripts/kconfig/zconf.lex.c_shipped > scripts/kconfig/zconf.lex.c
echo ' SHIPPED scripts/kconfig/zconf.hash.c'; cat scripts/kconfig/zconf.hash.c_shipped > scripts/kconfig/zconf.hash.c
set -e; echo ' HOSTCC scripts/kconfig/zconf.tab.o'; cc -Wp,-MD,scripts/kconfig/.zconf.tab.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DCURSES_LOC="" -DNCURSES_WIDECHAR=1 -DLOCALE -Iscripts/kconfig -c -o scripts/kconfig/zconf.tab.o scripts/kconfig/zconf.tab.c; scripts/basic/fixdep scripts/kconfig/.zconf.tab.o.d scripts/kconfig/zconf.tab.o 'cc -Wp,-MD,scripts/kconfig/.zconf.tab.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DCURSES_LOC="" -DNCURSES_WIDECHAR=1 -DLOCALE -Iscripts/kconfig -c -o scripts/kconfig/zconf.tab.o scripts/kconfig/zconf.tab.c' > scripts/kconfig/.zconf.tab.o.tmp; rm -f scripts/kconfig/.zconf.tab.o.d; mv -f scripts/kconfig/.zconf.tab.o.tmp scripts/kconfig/.zconf.tab.o.cmd
set -e; echo ' HOSTLD scripts/kconfig/conf'; cc -o scripts/kconfig/conf scripts/kconfig/conf.o scripts/kconfig/zconf.tab.o ; printf '%s\n' 'cmd_scripts/kconfig/conf := cc -o scripts/kconfig/conf scripts/kconfig/conf.o scripts/kconfig/zconf.tab.o ' > scripts/kconfig/.conf.cmd
scripts/kconfig/conf --defconfig=arch/../configs/nanopi_neo2_defconfig Kconfig
也可以通过make nanopi_neo2_defconfig V=1
命令查看编译过程中的详细输出
make -f ./scripts/Makefile.build obj=scripts/basic
cc -Wp,-MD,scripts/basic/.fixdep.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -o scripts/basic/fixdep scripts/basic/fixdep.c
rm -f .tmp_quiet_recordmcount
make -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfig
cc -Wp,-MD,scripts/kconfig/.conf.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DCURSES_LOC="" -DNCURSES_WIDECHAR=1 -DLOCALE -c -o scripts/kconfig/conf.o scripts/kconfig/conf.c
cat scripts/kconfig/zconf.tab.c_shipped > scripts/kconfig/zconf.tab.c
cat scripts/kconfig/zconf.lex.c_shipped > scripts/kconfig/zconf.lex.c
cat scripts/kconfig/zconf.hash.c_shipped > scripts/kconfig/zconf.hash.c
cc -Wp,-MD,scripts/kconfig/.zconf.tab.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DCURSES_LOC="" -DNCURSES_WIDECHAR=1 -DLOCALE -Iscripts/kconfig -c -o scripts/kconfig/zconf.tab.o scripts/kconfig/zconf.tab.c
cc -o scripts/kconfig/conf scripts/kconfig/conf.o scripts/kconfig/zconf.tab.o
scripts/kconfig/conf --defconfig=arch/../configs/nanopi_neo2_defconfig Kconfig
#
# configuration written to .config
#
下面根据上述内容,对照Makefile源码进行分析
执行make nanopi_neo2_defconfig V=1
时,编译目标为nanopi_neo2_defconfig
,即MAKECMDGOALS = nanopi_neo2_defconfig
在Makefile源码中搜索:defconfig:
无相关项,搜索config:
有两处匹配
对应Makefile中源码为
根据上一章3.16节的分析,当执行make xxx_defconfig
时,此时config-targets = 1, mixed-targets = 0, dot-config = 1
,满足第467行条件 ,因此分支有效。
根据编译目标MAKECMDGOALS = nanopi_neo2_defconfig
,与第478行匹配(其中%
为通配符),即nanopi_neo2_defconfig
依赖项为scripts_basic outputmakefile FORCE
,其中FORCE
在第1702行定义
FORCE
的依赖项与执行语句均为空,即为没有命令或者依赖的规则,这样的规则每次在执行时,目标总会被认为是最新的(更新过的),因此当它被作为其它规则的依赖时,由于FORCE
总是被认为是更新过的,所以在FORCE
所在的规则中定义的命令总会被执行
也就是说,由于FORCE
是没有命令或者依赖的规则,而nanopi_neo2_defconfig
依赖项包含FORCE
,每次都会执行nanopi_neo2_defconfig
规则的命令
将Makefile源码中的变量替换为其值,得到nanopi_neo2_defconfig
规则的全貌(其中$@
为Makefile的自动化变量,表示目前规则中所有的目标的集合)
nanopi_neo2_defconfig: scripts_basic outputmakefile FORCE
make -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfig
对于依赖项outputmakefile
,根据上一章分析可知为空,因此
nanopi_neo2_defconfig: scripts_basic FORCE
make -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfig
搜索Makefile中scripts_basic
规则,仅有一处
scripts_basic
规则没有依赖项,其命令为(-f
为指定其它文件为描述文件)
scripts_basic:
make -f ./scripts/Makefile.build obj=scripts/basic
rm -f .tmp_quiet_recordmcount
对应命令序列的第1行和第3行,也即编译过程中输出信息的第1行和第3行
后续对./scripts/Makefile.build
文件进行分析
第9行~17行,定义了2个变量,这里obj
在执行命令时输入,为scripts/basic
最终结果为
prefix = .
src = scripts/basic
第19行~54行,定义PHONY
等变量,并包含一些文件
PHONY
为第一个出现的规则,也为默认规则,实际上的默认目标为其依赖项__build
,在这里__build
暂时为空
第57行~59行,定义了kbuild-file
并包含。
首先是kbuild-dir
的赋值,这里if
语句不满足条件,因此kbuild-dir
的值为后半部分$(srctree)/$(src)
,即kbuild-dir = ./scripts/basic
而./scripts/basic
目录下无Kbuild
文件,因此58行的if
语句不满足条件,kbuild-file
的值为后半部分$(kbuild-dir)/Makefile
,即kbuild-file = ./scripts/basic/Makefile
第59行包含此Makefile
查找__build
,在**第116行119行**定义了依赖项和规则,116行118行为依赖项,119行为规则
这里KBUILD_BUILTIN
、KBUILD_MODULES
在顶层Makefile中定义:KBUILD_BUILTIN :=1
、KBUILD_MODULES :=
,因此__build
规则为
__build: $(builtin-target) $(lib-target) $(extra-y) $(subdir-ym) $(always)
@:
builtin-target
在第108行~110行定义
其中obj-y
、obj-m
、obj-
、subdir-m
、extra-y
、subdir-ym
均为空,则lib-target
、builtin-target
也为空
因此__build
规则为
__build: $(always)
@:
always
在./scripts/basic/Makefile
(根据前面的分析,在Makefile.build的第59行使用include
关键字调用量,因此在第59行会先执行此Makefile文件中的内容)中赋值为always := $(hostprogs-y)
,而hostprogs-y := fixdep
,并增加obj
的值作为前缀
故always = scripts/basic/fixdep
,因此__build
规则最终为
__build: scripts/basic/fixdep
@:
因此__build
规则也即scripts_basic
规则最终结果为生成fixdep
,根据注释可知,fixdep是用于编译其它的宿主机程序
使用grep命令grep -rnw fixdep
搜索fixdep关键字
可以看到在scripts/Makefile.build
文件中存在相应规则
可知fixdep
通过调用make-cmd
函数,输入参数为cc_o_c
编译而来;搜索make-cmd
关键字,在scripts/Kbuild.include
中有定义
可知在make-cmd
中,输入参数将组合成cmd_$(1)
,即cmd_cc_o_c
;在scripts/
路径下搜索cmd_cc_o_c
根据前述分析可知未定义CONFIG_MODVERSIONS
,因此cmd_cc_o_c
命令如下,其中@$
为自动化变量,表示目标集合,@<
表示所有的依赖集合
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
结合编译输出
make -f ./scripts/Makefile.build obj=scripts/basic
cc -Wp,-MD,scripts/basic/.fixdep.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -o scripts/basic/fixdep scripts/basic/fixdep.c
即使用CC
命令,将scripts/basic/fixdep.c
编译为scripts/basic/fixdep
另:(通过gcc -v --help可以查看所有
用法)
-Wp,
将逗号分隔的
传递给预处理器(preprocessor);-MD,scripts/basic/.fixdep.d
生成文件关联信息,包含目标文件所依赖的所有源代码,将输出导入到.d
文件里面;-Wall
生成所有警告信息;-Wstrict-prototypes
Warn about unprototyped function declarations;-O0
不做任何优化,这是默认的编译选项;-O1
优化会消耗少多的编译时间,它主要对代码的分支,常量以及表达式等进行优化;-O2
会尝试更多的寄存器级的优化以及指令级的优化,它会在编译期间占用更多的内存和编译时间;-O3
在 O2 的基础上进行更多的优化,例如使用伪寄存器网络,普通函数的内联,以及针对循环的更多优化;-Os
主要是对代码大小的优化,我们基本不用做更多的关心。`-O0`不做任何优化,这是默认的编译选项;
`-Os`和`-O1`对程序做部分编译优化,对于大函数,优化编译占用稍微多的时间和相当大的内存。使用本项优化,编译器会尝试减小生成代码的尺寸,以及缩短执行时间,但并不执行需要占用大量编译时间的优化;
`-O2`是比 O1 更高级的选项,进行更多的优化,Gcc 将执行几乎所有的不包含时间和空间折中的优化。当设置 O2 选项时,编译器并不进行循环打开 loop unrolling 以及函数内联。与 O1 比较而言,O2 优化增加了编译时间的基础上,提高了生成代码的执行效率;
`-O3`比 O2 更进一步的进行优化,打开`-finline-functions`、`-fweb`、`-frename-registers`、`-funswitch-loops`优化选项,即使用伪寄存器网络,普通函数的内联,以及针对循环的更多优化
任何级别的优化都将带来代码结构的改变。例如:对分支的合并和消除,对公用子表达式的消除,对循环内 load/store 操作的替换和更改等,都将会使目标代码的执行顺序变得面目全非,导致调试信息严重不足;在 O2 优化后,编译器会对影响内存操作的执行顺序
上述分析已经执行make nanopi_neo2_defconfig
所需依赖目标scripts_basic
进行了分析,结果为生成fixdep
工具
nanopi_neo2_defconfig: scripts_basic FORCE
make -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfig
现在来看后续的命令语句
make -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfig
根据3.2.1节和3.2.2节中对./scripts/Makefile.build
文件的分析,各变量取值为
obj = scripts/kconfig
prefix = .
src = scripts/kconfig
kbuild-dir = scripts/kconfig
kbuild-file = scripts/kconfig/Makefile
第59行通过include $(kbuild-file)
语句调用scripts/kconfig/Makefile
,目标为nanopi_neo2_defconfig
,因此在文件中查找关键字defconfig
可知在第120行存在目标规则匹配
根据文件内变量取值,此规则翻译如下,其中$<
表示依赖项的挨个值,这里只有一个,即scripts/kconfig/conf
nanopi_neo2_defconfig: scripts/kconfig/conf
scripts/kconfig/conf --defconfig=arch/../configs/nanopi_neo2_defconfig Kconfig
结合编译过程的输出,可知通过如下过程,编译出所需的conf
工具
(conf
工具主要由conf.c
、zconf.tab.c
、zconf.lex.c
、zconf.hash.c
几个文件编译而来;其中zconf.tab.c
-Bison解析器、zconf.lex.c
-flex解析器、zconf.hash.c
-哈希解析器?,从名字可知为不同解析器的函数源码;main
函数在conf.c
中)
make -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfig
cc -Wp,-MD,scripts/kconfig/.conf.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DCURSES_LOC="" -DNCURSES_WIDECHAR=1 -DLOCALE -c -o scripts/kconfig/conf.o scripts/kconfig/conf.c
cat scripts/kconfig/zconf.tab.c_shipped > scripts/kconfig/zconf.tab.c
cat scripts/kconfig/zconf.lex.c_shipped > scripts/kconfig/zconf.lex.c
cat scripts/kconfig/zconf.hash.c_shipped > scripts/kconfig/zconf.hash.c
cc -Wp,-MD,scripts/kconfig/.zconf.tab.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DCURSES_LOC="" -DNCURSES_WIDECHAR=1 -DLOCALE -Iscripts/kconfig -c -o scripts/kconfig/zconf.tab.o scripts/kconfig/zconf.tab.c
cc -o scripts/kconfig/conf scripts/kconfig/conf.o scripts/kconfig/zconf.tab.o
然后使用此conf
工具,执行
scripts/kconfig/conf --defconfig=arch/../configs/nanopi_neo2_defconfig Kconfig
根据conf.c
的main
函数,通过输入参数获取配置文件路径,然后调用conf_read
函数读取文件内容,再调用conf_write
,将内容写入默认的.config
文件中
故make nanopi_neo2_defconfig
命令将生成fixdep
、conf
两个工具,
然后根据默认的配置文件nanopi_neo2_defconfig
生成U-Boot根目录下的.config
文件
完结撒花✿✿ヽ(°▽°)ノ✿