【嵌入式移植】5、U-Boot源码分析2—make nanopi_neo2_defconfig

U-Boot源码分析2---make nanopi_neo2_defconfig

  • [1 概述](#1 概述)
  • [2 nanopi_neo2_defconfig](#2 nanopi_neo2_defconfig)
  • [3 编译过程分析](#3 编译过程分析)
    • [3.1 编译目标](#3.1 编译目标)
    • [3.2 scripts_basic](#3.2 scripts_basic)
    • [3.2.1 prefix src定义](#3.2.1 prefix src定义)
    • [3.2.2 PHONY](#3.2.2 PHONY)
    • [3.2.3 __build](#3.2.3 __build)
    • [3.2.4 fixdep](#3.2.4 fixdep)
    • [3.3 obj=scripts/kconfig](#3.3 obj=scripts/kconfig)

1 概述

上一章中,对Makefile相关源码进行了初步分析,这里结合编译过程具体分析其执行过程。

2 nanopi_neo2_defconfig

nanopi_neo2_defconfig文件位于./config/目录下,内容如下

bash 复制代码
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

3 编译过程分析

首先通过make nanopi_neo2_defconfig -n命令,-n表示仅输出执行过程中的命令序列,而不真正执行

bash 复制代码
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="<ncurses.h>" -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="<ncurses.h>" -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="<ncurses.h>" -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="<ncurses.h>" -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命令查看编译过程中的详细输出

bash 复制代码
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="<ncurses.h>" -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="<ncurses.h>" -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源码进行分析

3.1 编译目标

执行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的自动化变量,表示目前规则中所有的目标的集合)

bash 复制代码
nanopi_neo2_defconfig: scripts_basic outputmakefile FORCE
	make -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfig

对于依赖项outputmakefile,根据上一章分析可知为空,因此

bash 复制代码
nanopi_neo2_defconfig: scripts_basic FORCE
	make -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfig

3.2 scripts_basic

搜索Makefile中scripts_basic规则,仅有一处

scripts_basic规则没有依赖项,其命令为(-f为指定其它文件为描述文件)

bash 复制代码
scripts_basic:
	make -f ./scripts/Makefile.build obj=scripts/basic
	rm -f .tmp_quiet_recordmcount

对应命令序列的第1行和第3行,也即编译过程中输出信息的第1行和第3行

后续对./scripts/Makefile.build文件进行分析

3.2.1 prefix src定义

第9行~17行 ,定义了2个变量,这里obj在执行命令时输入,为scripts/basic

最终结果为

bash 复制代码
prefix = .
src = scripts/basic

3.2.2 PHONY

第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

3.2.3 __build

查找__build,在**第116行119行**定义了依赖项和规则,116行118行为依赖项,119行为规则

这里KBUILD_BUILTINKBUILD_MODULES在顶层Makefile中定义:KBUILD_BUILTIN :=1 KBUILD_MODULES :=,因此__build规则为

bash 复制代码
__build: $(builtin-target) $(lib-target) $(extra-y) $(subdir-ym) $(always)
	@:

builtin-target在第108行~110行定义

其中obj-yobj-mobj-subdir-mextra-ysubdir-ym均为空,则lib-targetbuiltin-target也为空

因此__build规则为

bash 复制代码
__build: $(always)
	@:

always./scripts/basic/Makefile(根据前面的分析,在Makefile.build的第59行使用include关键字调用量,因此在第59行会先执行此Makefile文件中的内容)中赋值为always := $(hostprogs-y),而hostprogs-y := fixdep,并增加obj的值作为前缀

always = scripts/basic/fixdep,因此__build规则最终为

bash 复制代码
__build: scripts/basic/fixdep
	@:

因此__build规则也即scripts_basic规则最终结果为生成fixdep,根据注释可知,fixdep是用于编译其它的宿主机程序

3.2.4 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命令如下,其中@$为自动化变量,表示目标集合,@<表示所有的依赖集合

bash 复制代码
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<

结合编译输出

bash 复制代码
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可以查看所有 <options >用法)

  • -Wp, <option>将逗号分隔的 <options >传递给预处理器(preprocessor);-MD,scripts/basic/.fixdep.d生成文件关联信息,包含目标文件所依赖的所有源代码,将输出导入到.d文件里面;
  • -Wall生成所有警告信息;
  • -Wstrict-prototypesWarn about unprototyped function declarations;
  • -O0不做任何优化,这是默认的编译选项;
  • -O1优化会消耗少多的编译时间,它主要对代码的分支,常量以及表达式等进行优化;
  • -O2会尝试更多的寄存器级的优化以及指令级的优化,它会在编译期间占用更多的内存和编译时间;
  • -O3在 O2 的基础上进行更多的优化,例如使用伪寄存器网络,普通函数的内联,以及针对循环的更多优化;
  • -Os主要是对代码大小的优化,我们基本不用做更多的关心。
bash 复制代码
`-O0`不做任何优化,这是默认的编译选项;
`-Os`和`-O1`对程序做部分编译优化,对于大函数,优化编译占用稍微多的时间和相当大的内存。使用本项优化,编译器会尝试减小生成代码的尺寸,以及缩短执行时间,但并不执行需要占用大量编译时间的优化;
`-O2`是比 O1 更高级的选项,进行更多的优化,Gcc 将执行几乎所有的不包含时间和空间折中的优化。当设置 O2 选项时,编译器并不进行循环打开 loop unrolling 以及函数内联。与 O1 比较而言,O2 优化增加了编译时间的基础上,提高了生成代码的执行效率;
`-O3`比 O2 更进一步的进行优化,打开`-finline-functions`、`-fweb`、`-frename-registers`、`-funswitch-loops`优化选项,即使用伪寄存器网络,普通函数的内联,以及针对循环的更多优化

任何级别的优化都将带来代码结构的改变。例如:对分支的合并和消除,对公用子表达式的消除,对循环内 load/store 操作的替换和更改等,都将会使目标代码的执行顺序变得面目全非,导致调试信息严重不足;在 O2 优化后,编译器会对影响内存操作的执行顺序

3.3 obj=scripts/kconfig

上述分析已经执行make nanopi_neo2_defconfig所需依赖目标scripts_basic进行了分析,结果为生成fixdep工具

bash 复制代码
nanopi_neo2_defconfig: scripts_basic FORCE
	make -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfig

现在来看后续的命令语句

bash 复制代码
	make -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfig

根据3.2.1节和3.2.2节中对./scripts/Makefile.build文件的分析,各变量取值为

bash 复制代码
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

bash 复制代码
nanopi_neo2_defconfig: scripts/kconfig/conf
	scripts/kconfig/conf --defconfig=arch/../configs/nanopi_neo2_defconfig Kconfig

结合编译过程的输出,可知通过如下过程,编译出所需的conf工具

conf工具主要由conf.czconf.tab.czconf.lex.czconf.hash.c几个文件编译而来;其中zconf.tab.c-Bison解析器、zconf.lex.c-flex解析器、zconf.hash.c-哈希解析器?,从名字可知为不同解析器的函数源码;main函数在conf.c中)

bash 复制代码
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="<ncurses.h>" -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="<ncurses.h>" -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工具,执行

bash 复制代码
scripts/kconfig/conf  --defconfig=arch/../configs/nanopi_neo2_defconfig Kconfig

根据conf.cmain函数,通过输入参数获取配置文件路径,然后调用conf_read函数读取文件内容,再调用conf_write,将内容写入默认的.config文件中

make nanopi_neo2_defconfig命令将生成fixdepconf两个工具,

然后根据默认的配置文件nanopi_neo2_defconfig生成U-Boot根目录下的.config文件

完结撒花✿✿ヽ(°▽°)ノ✿

相关推荐
charlie1145141911 小时前
Cinux: 加载第一个内核:从 bootloader 跳进 C++
linux·开发语言·c++·嵌入式
dddwjzx7 小时前
嵌入式Linux C应用编程入门——标准IO库
嵌入式
pai同学7 小时前
ESP-IDF+vscode开发ESP32第十二讲——event
嵌入式
凉、介8 小时前
KVM + QEMU 虚拟化
笔记·学习·嵌入式·arm·qemu·虚拟化·kvm
dddwjzx1 天前
嵌入式Linux C应用编程入门——文件IO进阶
嵌入式
2023自学中1 天前
imx6ull 开发板, mame 模拟器,运行游戏 测试
linux·游戏·嵌入式·开发板
dddwjzx1 天前
嵌入式Linux C应用编程入门——文件IO
嵌入式
fzm52981 天前
车载ECU单元测试技术与应用研究
c语言·自动化测试·单元测试·嵌入式·白盒测试
用户120487221613 天前
Linux驱动编译与加载
linux·嵌入式
用户805533698033 天前
Input 子系统架构:Core、Handler、Driver 三层是怎么协作的
linux·嵌入式