Uboot 中make menuconfig 做了什么?

Posted syyxy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Uboot 中make menuconfig 做了什么?相关的知识,希望对你有一定的参考价值。

Make menuconfig  到底做了什么?

(写在前面: 本文是本人分析uboot中的makefile文件得到的粗浅的见解,写的越多越感觉其中的深奥复杂。本文是编辑在word中粘贴过来的, 排版可能有有点问题, 或者可以下载 https://files.cnblogs.com/files/syyxy/make_menuconfig%E5%88%B0%E5%BA%95%E5%81%9A%E4%BA%86%E4%BB%80%E4%B9%88%EF%BC%9F.zip 这个是我的原版,排版会好一些)

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

%config: scripts_basic outputmakefile FORCE

$(MAKE) $(build)=scripts/kconfig [email protected]

 

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

scripts_basic:

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

    rm -f .tmp_quiet_recordmcount

 

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

 技术分享图片

 

则将其展开得到:

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了下来

 技术分享图片

技术分享图片

 

那么 $(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 文件中找到其定义如下:

 技术分享图片

 

和:

 技术分享图片

 

 

首先看:

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 中 只有一处定义:

 技术分享图片

 

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

 

通过查看各个文件, 在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 ,这个文件。

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

 

通过 $(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

 

可以看到:

 技术分享图片

 

 

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

_build 为 scripts/basic/fixdep

 

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

 技术分享图片

 

 

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

 技术分享图片

 

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

 

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

scripts_basic: scripts/basic/fixdep

outputmakefile: 空

FORCE :代表强制执行

 

 

接下来就是:

 

 技术分享图片

 

$(MAKE) $(build)=scripts/kconfig [email protected]

 

如果我们输入 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.host 的 118 行, 可以看到如下定义:

$(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 ‘ ‘[email protected] := $(make-cmd)‘ > $(dot-target).cmd)

 

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

 技术分享图片

 

因此我们这里就间接解释了 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/Makefile 第201行, 定义如下:

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.host 第105行有如下定义:

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

# host-cmulti -> executable

quiet_cmd_host-cmulti   = HOSTLD  [email protected]

cmd_host-cmulti = $(HOSTCC) $(HOSTLDFLAGS) -o [email protected]

              $(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 ‘ ‘[email protected] := $(make-cmd)‘ > $(dot-target).cmd)

 

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

 技术分享图片

 

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

使用:

scripts/kconfig/mconf  Kconfig

就得到了我们的界面:

 技术分享图片

 

 

 

完成!

 

 

 

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

以上是关于Uboot 中make menuconfig 做了什么?的主要内容,如果未能解决你的问题,请参考以下文章

make: *** 没有规则可以创建目标“menuconfig”

make menuconfig通常设置哪些参数

Linux——使用图形化内核配置工具,执行make menuconfig时出现“make: *** No rule to make target ‘menuconfig‘. Stop.”

Linux——使用图形化内核配置工具,执行make menuconfig时出现“make: *** No rule to make target ‘menuconfig‘. Stop.”

make menuconfig显示错误“Your display is too small to run Menuconfig!”

如何用make menuconfig配置kernel