Makemenuconfig到底做了什么?

 

转载地址:https://www.cnblogs.com/syyxy/p/9350999.html

在Uboot的主Makefile中496行可以看到如下定义:

%config: scripts_basic outputmakefile FORCE

$(MAKE)$(build)=scripts/kconfig $@

 

在Makefile 415行中可以看到如下定义:

scripts_basic:

    $(MAKE) $(build)=scripts/basic

    rm -f .tmp_quiet_recordmcount

 

$(build) script/Kbuild.include文件中下定义如下:

Makemenuconfig到底做了什么?_第1张图片

则将其展开得到:

Make -f scripts/Makefile.build obj=srcipts/basic

 

由于没有指定目标,因此__build为默认目标

 

__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \

     $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \

     $(subdir-ym) $(always)

@:

 

 

解析:

$(KBUILD_BUILTIN): 在根目录的makefile, 将其置为了1,且被export了下来

Makemenuconfig到底做了什么?_第2张图片

 

那么$(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y))

返回的结果就是$(builtin-target) $(lib-target) $(extra-y)

 

$(KBUILD_MODULES):在根目录中设置了为0, 且被export了下来.因此:

$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target))的返回值就是空。则__build可以写作:

__build:$(builtin-target) $(lib-target) $(extra-y)$(subdir-ym)$(always)

 

接下来分析依赖文件:

$(builtin-target)在Makefile.build 文件中找到其定义如下:

和:

Makemenuconfig到底做了什么?_第3张图片

 

首先看:

ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)

builtin-target := $(obj)/built-in.o

endif

 

如果没有定义 $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target),

builtin-target := $(obj)/built-in.o, 否则不定义该变量。

 

那么, 如何查看有没有定义这几个变量?

在我看来, 需要在3个地方查看变量的定义:

1)本makefile

2)是否是上层makefile 通过export的方式传递下来

3)有没有通过include 其他文件

 

首先查看$(obj-y):

在当前makefile.build 中只有一处定义:

Makemenuconfig到底做了什么?_第4张图片

 

但是我们仍然还要看此Makefileinclude了那几个文件,如下:

Makemenuconfig到底做了什么?_第5张图片

通过查看各个文件,Makefile.lib 中发现如下定义:

obj-y      := $(patsubst %/, %/built-in.o, $(obj-y))

obj-y      := $(addprefix $(obj)/,$(obj-y))

通过以上可以看出,上面的使用仍然需要$(obj-y)。因此不是我们的目标(请注意,我们此阶段的目标是找到$(obj-y)的具体定义)

Makefile.build中发现如下片段:

# Do not include host rules unless needed

ifneq ($(hostprogs-y)$(hostprogs-m),)

include scripts/Makefile.host

endif

接下来就是确定有没有定义$(hostprogs-y)$(hostprogs-m),这两个变量。

 

通过$(error  $(hostprogs-y))打印$(hostprogs-y)为dep

则说明确实定义了$(hostprogs-y),则会include scripts/Makefile.host,这个文件。

查看该文件并没有定义该变量。

 

由此看来,$(obj-y) 为空

上述只是告诉了分析方法,其实可以通过打印的方式打印出来,如下:

 

PHONY += scripts_basic

scripts_basic:

    $(Q) echo "obj-y:"$(obj-y)

    $(Q)$(MAKE) $(build)=scripts/basic

    $(Q)rm -f .tmp_quiet_recordmcount

 

可以看到:

Makemenuconfig到底做了什么?_第6张图片

 

同理,通过添加$(error  xxxxx)可以轻松得到变量的值

_build scripts/basic/fixdep

 

接下来的依赖目标是:outputmakefile,我们没有定义$(KBUILD_SRC),因此outputmakefile为空。

Makemenuconfig到底做了什么?_第7张图片

 

接下来依赖的目标是:FORCE, 定义如下:

可以看到FORCE 为伪目标,强制执行。

 

到这里%config的三个依赖目标全部得到了:

scripts_basic: scripts/basic/fixdep

outputmakefile:

FORCE :代表强制执行

 

 

接下来就是:

 

$(MAKE) $(build)=scripts/kconfig $@

 

如果我们输入make menuconfig,

将其展开,得到:

make -f ./scripts/Makefile.build obj=scripts/kconfig menuconfig

 

这里做了什么?

首先我们要知道,./scripts/Makefile.build,

$(obj)= scripts/kconfig

分析该文件开头代码,

 

# Modified for U-Boot

prefix := tpl

src := $(patsubst $(prefix)/%,%,$(obj))

ifeq ($(obj),$(src))

prefix := spl

src := $(patsubst $(prefix)/%,%,$(obj))

ifeq ($(obj),$(src))

prefix := .

endif

endif

 

分析:

src := $(patsubst $(prefix)/%,%,$(obj))

意思是:如果,$(obj)中有单词符合tpl/* ,则将其替换为*(例如将 tpl/test替换为 test)。并将替换结果返回(注意,该结果包括不能替换的单词)

因此得到src=scripts/kconfig

 

然后继续往下走:

 

# The filename Kbuild has precedence over 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)

 

分析:

$(if $(filter /%,$(src)),$(src),$(srctree)/$(src))

意思是:保留$(src)中以/开头的单词,如果为空(),则返回$(srctree)/$(src),否则返回$(src)

$(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)

意思是:如果$(kbuild-dir)/Kbuild存在,则返回 $(kbuild-dir)/Kbuild,否则返回 $(kbuild-dir)/makefile.通过查看./scripts/kconfig目录下没有kbuild文件,那么kbuild-file 就是./scripts/kconfig /makefile

得到:

kbuild-dir = ./scripts/kconfig

kbuild-file =./scripts/kconfig/makefile

 

然后将其include 进来。

 

到这里其实不用往下看了, 因为我们需要分析的目标menuconfig, 就在./scripts/basic/makefile中。

 

menuconfig: $(obj)/mconf

    $<$(silent)$(Kconfig)

 

Menuconfig 依赖 ./scripts/basic/mconf 目标

 

那么mconf是如何编译的呢?

 

我们在当前Makefile搜索,发现mconf赋给了变量hostprogs-y(205):

hostprogs-y := conf nconf mconf kxgettext qconf gconf

 

而我们include scripts/Makefile.host ,可以看到hostprogs-y赋给了__hostprogs:

__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))

scripts/Makefile.host的第42,可以看到:

 

# Object (.o) files compiled from .c files

host-cobjs  := $(sort $(foreach m,$(__hostprogs),$($(m)-objs)))

64行可以看到:

 

host-cobjs  := $(addprefix $(obj)/,$(host-cobjs))

 

而在scripts/Makefile.host118 ,可以看到如下定义:

$(host-cobjs): $(obj)/%.o: $(src)/%.c FORCE

    $(call if_changed_dep,host-cobjs)

 

我们将 $(obj)$(src)在这个目标的下方使用$(warning $(obj))$(warning $(src))打印出来:

 

$(host-cobjs)打印出来:

 

因此我们这里就将scripts/kconfig下的所有的*.c文件编译成了.o

 

$(if_change_dep) 的定义在scripts/Kbuild.include 256:

# Execute command if command has changed or prerequisite(s) are updated.

#

if_changed = $(if $(strip $(any-prereq) $(arg-check)),                       \

    @set -e;                                                             \

    $(echo-cmd) $(cmd_$(1));                                             \

    printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)

 

我们将@set -e;   去掉@可以看到打印:

Makemenuconfig到底做了什么?_第8张图片

 

因此我们这里就间接解释了HOSTCC  scripts/kconfig/mconf.o这样的整齐划一的打印从哪里来的。

 

目前我们知道了如何将*conf.c 编译为.o 那么如何链接,生成真正的工具的呢?

 

请看host-cmulti这个变量。

 

# C executables linked based on several .o files

host-cmulti := $(foreach m,$(__hostprogs),\

           $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m))))

 

我们来分析一下这个语句:

$(foreach m,$(__hostprogs),\

           $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m))))

 

首先找到make foreach 的定义:

https://www.cnblogs.com/rohens-hbg/p/6297495.html

从上面的解释中,我们可以将我们的语句翻译为:

遍历$(__hostprogs)中的变量,放到m,然后执行$(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m)))。将得到的返回值赋给host-cmulti

$(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m)))翻译为:

如果 $($(m)-cxxobjs)存在,则返回空,否则返回$(if $($(m)-objs),$(m))

$(if $($(m)-objs),$(m))翻译为:

如果$($(m)-objs)存在则返回$(m)

 

目前我们已知$(__hostprogs)=conf gconf kxgettext mconf nconf qconf

那么根据上诉逻辑一步一步走,可以得到:

host-cmulti=conf gconf kxgettext mconf nconf

 

有人会问,为什么少了qconf?

因为在srcipts/kconfig/Makefile201,定义如下:

qconf-cxxobjs   := qconf.o

因此被消除了。

 

目前我们得到了:

host-cmulti =conf gconf kxgettext mconf nconf

 

我们可以在srcipts/Makefile.host中查看host-cmulti的变化过程:

在第62,被添加了前缀:

host-cmulti := $(addprefix $(obj)/,$(host-cmulti))

得到:

host-cmulti = scripts/kconfig/conf scripts/kconfig/gconf scripts/kconfig/kxgettext scripts/kconfig/mconf scripts/kconfig/nconf

在第107, host-cmulti被当成目标强制编译,过程为:

$(host-cmulti): FORCE

    $(call if_changed,host-cmulti)

 

也就是说,只要有目标是scripts/kconfig/conf scripts/kconfig/gconf scripts/kconfig/kxgettext scripts/kconfig/mconf scripts/kconfig/nconf

这些,就会走 $(call if_changed,host-cmulti)流程。

 

目前我们得到了

host-cmulti = scripts/kconfig/conf scripts/kconfig/gconf scripts/kconfig/kxgettext scripts/kconfig/mconf scripts/kconfig/nconf

 

scripts/Makefile.host105行有如下定义:

# Link an executable based on list of .o files, all plain c

# host-cmulti -> executable

quiet_cmd_host-cmulti   = HOSTLD  $@

cmd_host-cmulti = $(HOSTCC)$(HOSTLDFLAGS) -o $@ \

              $(addprefix $(obj)/,$($(@F)-objs)) \

              $(HOST_LOADLIBES)$(HOSTLOADLIBES_$(@F))

 

紧接着下一行有:

$(host-cmulti): FORCE

    $(call if_changed,host-cmulti)

$(warning $(host-cmulti))

$(call multi_depend, $(host-cmulti), , -objs)

 

$(if_changed  )的定义在scripts/Makefile.include 356行:

# Execute command if command has changed or prerequisite(s) are updated.

#

if_changed = $(if $(strip $(any-prereq) $(arg-check)),                       \

    @set -e;                                                             \

    $(echo-cmd) $(cmd_$(1));                                             \

    printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)

 

我们将@去掉得到如下打印:

可以看到编译过程cc  -o scripts/kconfig/mconf. 至此, mconf 这个文件我们已经得到了。

使用:

scripts/kconfig/mconf  Kconfig

就得到了我们的界面:

Makemenuconfig到底做了什么?_第9张图片

 

 

完成!

 

 

 

接下来还有我们需要做的是如何添加和删除kconfig ?这就是下一篇博客需要做的了。

你可能感兴趣的:(uboot-makefile)