1. 程式人生 > >Uboot 中make menuconfig 做了什麽?

Uboot 中make menuconfig 做了什麽?

tcc err tput 說明 做的 utm image kcon 方法

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 $@

在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 $@

如果我們輸入 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\n‘ ‘cmd_$@ := $(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 $@

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

就得到了我們的界面:

技術分享圖片

完成!

接下來還有我們需要做的是如何添加和刪除kconfig ? 這就是下一篇博客需要做的了。

Uboot 中make menuconfig 做了什麽?