1. 读取顶层Makefile和scripts/Kbuild.include,由于如下规则,Makefile和Kbuild.include不会被应用隐式规则,无需编译
$(CURDIR)/Makefile Makefile: ; ... $(srctree)/scripts/Kbuild.include: ;
2. 开始编译menuconfig,由于顶层Makefile中的规则,menuconfig依赖于scripts_basic,outputmakefile和FORCE
%config: scripts_basic outputmakefile FORCE +$(Q)$(CONFIG_SHELL) $(srctree)/scripts/multiconfig.sh $@
scripts_basic用顶层Makefile中的规则进行编译:
$(build) 的定义scripts/Kbuild.include中:scripts_basic: $(Q)$(MAKE) $(build)=scripts/basic $(Q)rm -f .tmp_quiet_recordmcount
build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
也就是调用scripts/Makefile.build去编译,带有一个命令行参数obj=script/basic。由于没有指定编译目标,缺省的__build成为最优先的目标,__build依赖于always,always还有一个目标scripts/basic/fixdep,该目标在scripts/basic/Makefile中赋值给always和hostprogs-y。通过Makefile.host中的规则,生成fixdep。
__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m)) ... host-csingle := $(foreach m,$(__hostprogs),$(if $($(m)-objs),,$(m))) ... $(host-csingle): $(obj)/%: $(src)/%.c FORCE $(call if_changed_dep,host-csingle)
outputmakefile:无此目录
FORCE:伪目标
至此,menuconfig的依赖全部编译完成,开始调用multiconfig.sh,参数为menuconfig
在multiconfig.sh中,menuconfig的调用顺序是do_others() --> build(),这里build会调用scripts/Makefile.build编译menuconfig。在读取scripts/Makefile.build时,用如下规则读入了scripts/kconfig/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)
在scripts/kconfig/Makefile中用于编译mconf的规则如下:
menuconfig: $(obj)/mconf $< $(Kconfig)
在scripts/kconfig/Makefile中,mconf被置于hostprogs-y
而在Makefile.host中,hostprogs-y转变为host-cmulti,host-cmulti依赖于host-cobjs和host-cshliblxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o ... conf-objs := conf.o zconf.tab.o mconf-objs := mconf.o zconf.tab.o $(lxdialog) ... hostprogs-y := conf ... ifeq ($(MAKECMDGOALS),menuconfig) hostprogs-y += mconf endif
host-cobjs包含所有需要编译的*.o文件,因为host-cobjs被排序过,看到的顺序会和添加的顺序不一样。可以在Makefile.host中搜索host-cobjs看它是如何被添加的。__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m)) ... host-csingle := $(foreach m,$(__hostprogs),$(if $($(m)-objs),,$(m))) ... host-cmulti := $(foreach m,$(__hostprogs),\ $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m)))) ... $(host-cmulti): $(obj)/%: $(host-cobjs) $(host-cshlib) FORCE $(call if_changed,host-cmulti) ... $(host-cobjs): $(obj)/%.o: $(src)/%.c FORCE $(call if_changed_dep,host-cobjs)
host-cobjs被编译完成后,再通过host-cmulti的规则,编译出mconf,在编译mconf的时候会链接Ncurses,Ncurses是一个能提供功能键定义(快捷键),屏幕绘制以及基于文本终端的图形互动功能的动态库。conf虽然是hostprogs-y中的目标,但是和生成menuconfig无关,所以没有被编译。mconf编译成功后,会被直接调用,并传递参数$(Kconfig),生成menuconfig的界面。
3. 不过,在编译u-boot的时候没有强制要求一定要使用menuconfig,而且大部分的config都是空的。
注:我在u-boot-2014.10的Makefile和Kbuild文件中加了一些注释,如果感兴趣,可以点下面的链接下载。