还是先找到入口
上文《u-boot.bin生成过程追踪》,我们探讨了u-boot.bin的生成过程。在文章开头的地方,我们讲到终极目标,并且找到了主Makefile的终极目标所在。本文探讨u-boot.imx文件的生成,因很多内容跟上文都一样,所以在阅读本文之前,还需要阅读下上文的内容。
还是跟u-boot.bin一样,我们在ALL-y里面寻找u-boot.imx的定义。不过可惜,我们好像没找到,但是这是不可能的,如果ALL-y里面没有指定u-boot.imx,那么一定不会编译出u-boot.imx。我们不妨打印一下这个ALL-y看看,我在主Makefile802页加了一个打印,如下:
all: $(ALL-y)
@echo aaaaaaaaaaaaaaaaaa
@echo $(ALL-y)
@echo bbbbbbbbbbbbbbbbbb
我们看到如下输出:
aaaaaaaaaaaaaaaaaa
checkarmreloc u-boot.imx u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check
bbbbbbbbbbbbbbbbbb
看到没有,这里是有u-boot.imx的。那么这个是在哪里加入的呢?这里我们就要略微动下脑子了,这个u-boot.imx后缀是imx,而且我们清楚,这个东西是NXP imx平台特有的一个uboot镜像,所以这个东西不大可能在主Makefile里面直接写进去。那一定是跟平台相关的,但是跟平台相关,东西也挺多,要找这个玩意在哪里,也是有点困难啊。到了这里了,咱不得不祭出我们搜索的法宝,有需要的朋友可以拿去,挺好用的一个工具,命令如下:
sunke@droresrv:~/work/MYiR-iMX-Uboot$ find . -type f -name "*" | xargs grep "u-boot.imx"
这里我们全文递归查找字符串u-boot.imx。这里输出会比较多,我们把重要的输出拿出来看:
./arch/arm/config.mk:ALL-y += u-boot.imx
ifeq ($(CONFIG_OF_SEPARATE),y)
ALL-y += u-boot-dtb.imx
else
ALL-y += u-boot.imx
endif
看到没,这个config.mk里面追加了u-boot.imx到ALL-y变量里面。我们可以通过打印,验证一下,是否真的是这里引入了u-boot.imx。这里我也不列出来了,我打印了之后发现确实是这里引入的,大家可以自己试下。哪里引入的u-boot.imx我们知道了,这个u-boot.imx的构建规则入口又在哪里呢?我并没有在主Makefile里面找到u-boot.imx的规则,但是我找到了这条规则,主Makefile第839行:
%.imx: %.bin
$(Q)$(MAKE) $(build)=arch/arm/imx-common $@
这是个模式规则,u-boot.imx会匹配这个规则。这里又见到我们的老朋友build了,我们还是同样的方式,展开一下:
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.build obj=arch/arm/imx-common u-boot.imx
这里转向去执行Makefile.build,obj变量使Makefile.build会引入arch/arm/imx-common/Makefile,我们在这个Makefile里面找到了u-boot.imx规则,第57行:
u-boot.imx: u-boot.bin $(IMX_CONFIG) FORCE
$(call if_changed,mkimage)
怎么样,这个入口终于被我们找到了。
先看一下依赖
上面我们找到了u-boot.imx的入口,我们看到它依赖u-boot.bin,这个u-boot.bin我们已经在《u-boot.bin生成过程追踪》里面分析过了,想要追踪的可以看那里。另外,u-boot.imx还依赖$(IMX_CONFIG),我们通过打印的方式看到,这个展开之后如下:
board/myir/mys_imx6ull/imximage.cfg.cfgtmp
这个文件实际上是imx image header中的DCD数据,其规则定义在arch/arm/imx-common/Makfile里面,第48行,如下:
IMX_CONFIG = $(CONFIG_IMX_CONFIG:"%"=%).cfgtmp
其中定义了CONFIG_IMX_CONFIG变量,我们在include/autoconf.mk里面找到了这个变量的定义:
CONFIG_IMX_CONFIG="board/myir/mys_imx6ull/imximage.cfg"
$(IMX_CONFIG)还有一个规则,arch/arm/imx-common/Makfile第50行,如下:
quiet_cmd_cpp_cfg = CFGS $@
cmd_cpp_cfg = $(CPP) $(cpp_flags) -x c -o $@ $<
IMX_CONFIG = $(CONFIG_IMX_CONFIG:"%"=%).cfgtmp
$(IMX_CONFIG): %.cfgtmp: % FORCE
$(Q)mkdir -p $(dir $@)
$(call if_changed_dep,cpp_cfg)
这里$(IMX_CONFIG)这个目标是通过cpp_cfg命令生成的,我们可以看到,这个命令使用了$(CPP),CPP变量在主Makefile的第341行有定义,如下:
CPP = $(CC) -E
就是调用了gcc的-E选项而已,这个命令的详细展开及运行,大家可以自己分析一下,这里先不展开。我们重点看下u-boot.imx目标的命令。
再来看下命令
我们现在重点来展开分析u-boot.imx的命令,其调用了mkimage命令,这个通过if_changed函数展开之后,也就是命令cmd_mkimage。我们在Makefile.lib文件里面找到了这个命令的定义,Makefile.lib第435行,如下:
# Additional commands for U-Boot
#
# mkimage
# ---------------------------------------------------------------------------
quiet_cmd_mkimage = MKIMAGE $@
cmd_mkimage = $(objtree)/tools/mkimage $(MKIMAGEFLAGS_$(@F)) -d $< $@ \
$(if $(KBUILD_VERBOSE:1=), >/dev/null)
这个调用了tools/mkimage程序,我们展开一下这个变量的值:
./tools/mkimage $(MKIMAGEFLAGS_$(@F)) -d u-boot.bin u-boot.imx >/dev/null
这里面有个$(MKIMAGEFLAGS_$(@F)),其中$(@F)是表示目标文件的完整文件名中除目录以外的部分。在这里其值就是依赖文件u-boot.imx。于是这个变量就编程"$(MKIMAGEFLAGS_u-boot.imx)",这个变量在arch/arm/imx-common/Makefile里面定义,第54行:
MKIMAGEFLAGS_u-boot.imx = -n $(filter-out $< $(PHONY),$^) -T imximage \
-e $(CONFIG_SYS_TEXT_BASE)
这里我们直接展开如下:
MKIMAGEFLAGS_u-boot.imx = -n board/myir/mys_imx6ull/imximage.cfg.cfgtmp -T imximage -e 0x87800000
于是,整个cmd_mkimage命令展开就变成:
./tools/mkimage -n board/myir/mys_imx6ull/imximage.cfg.cfgtmp -T imximage -e 0x87800000 -d u-boot.bin u-boot.imx >/dev/null
看到没,这个就是最终生成u-boot.imx的命令,要看明白里面的具体生成过程,那么就需要去研究下mkimage程序的原理了。本文因为只追踪u-boot.imx的生成过程,具体生成原理这里就不赘述了,后续有机会分析uboot源代码时再详细展开吧。