uboot构建框架3-make menuconfig命令的过程追踪

menuconfig是uboot和内核配置的关键命令,用于选择CPU、SOC、特性等。通过make menuconfig启动图形配置界面,它并非直接在根目录Makefile中定义,而是通过模式规则匹配到scripts/kconfig/Makefile,最终由mconf程序执行生成配置界面。

menuconfig是干什么的?

编译过uboot或者内核的朋友一定清楚这个命令是干什么的,如果不知道,请记住了,这个命令是用来配置的。什么是配置?就是诸如选择什么CPU,选择什么soc,选择什么特性,是否编译成模块等等。uboot和内核的配置功能非常强大。menuconfig是一类通过ncurses实现的简易图形配置功能。

我们可以通过cd到uboot根目录,然后键入:

make menuconfig

就会出来一个图形配置界面:

然后,就可以通过按键来选择你需要的功能和特性,配置完成之后保存并退出。

menuconfig入口在哪里?

我们知道,make命令带上一个参数,make就会到Makefile里面找特定的目标。这里参数是menuconfig,那么make就会在根目录的Makefile里面去寻址menuconfig目标。我们打开根目录Makefile,很可惜,无论你怎么寻找,都没能找到目标是“menuconfig”的规则。

实际上,如果对make语法比较熟悉的话,你会发现,有一种叫做“模式规则”的东西,就是一个目标,并不是通过全名匹配,而是包含了模式字符'%'。这个'%'可以匹配任意非空字符串。如果研究过make help命令里面的各种命令,你会发现,类似make *config的命令还有好几个,远不止menuconfig这一个。但是都有个共同点,就是都以config结尾。比如:

Configuration targets:
  config          - Update current config utilising a line-oriented program
  nconfig         - Update current config utilising a ncurses menu based program
  menuconfig      - Update current config utilising a menu based program
  xconfig         - Update current config utilising a QT based front-end
  gconfig         - Update current config utilising a GTK based front-end
  oldconfig       - Update current config utilising a provided .config as base
  localmodconfig  - Update current config disabling modules not loaded
  localyesconfig  - Update current config converting local mods to core
  silentoldconfig - Same as oldconfig, but quietly, additionally update deps
  defconfig       - New config with default from ARCH supplied defconfig
  savedefconfig   - Save current config as ./defconfig (minimal config)
  allnoconfig     - New config where all options are answered with no
  allyesconfig    - New config where all options are accepted with yes
  allmodconfig    - New config selecting modules when possible
  alldefconfig    - New config with all symbols set to default
  randconfig      - New config with random answer to all options
  listnewconfig   - List new options
  olddefconfig    - Same as silentoldconfig but sets new symbols to their default value

我的天,居然有这么多。后面的简介说明了每个config是干嘛用的。这么多config,很显然如果每个都要在Makefile里面写一个规则,那也太重复了。于是,我们在根目录下的Makefile第473行,发现了这么一句:

config: scripts_basic outputmakefile FORCE
        $(Q)$(MAKE) $(build)=scripts/kconfig $@

%config: scripts_basic outputmakefile FORCE
        $(Q)$(MAKE) $(build)=scripts/kconfig $@

上面那个规则不是模式规则,完全匹配“config”。下面那条规则就匹配所有以config结尾的目标规则。这个规则依赖scripts_basic、outputmakefile和FORCE。具体这些依赖对应的规则,大家可以找一下看看,这里不展开了,看了之后其实非常简单的。这里我们需要重点研究一下这个命令。

menuconfig去到了哪里?

以上我们发现了menuconfig的入口,我们看这个规则的命令部分:

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

是不是用到了build?如果不清楚,请回头看下前一篇文章《kbuild框架简要分析》,我们将这个命令展开,得到:

$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.build obj=scripts/kconfig menuconfig

从这条命令我们知道,调用了子make命令,以Makefile.build为make输入规则,参数有两个,obj和menuconfig。好了,执行到这里,马上就要离开主Makefile了。我们进入Makefile.build。

首先,Makefile.build这个文件我们打开,发现里面语句还是挺多的,一下看不过来。还是那句话,先不管无关的东西,我们只关注我们代入的两个参数obj和menuconfig。Makefile.build开头,我们看到:

# 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

第三行,我们看到obj通过make函数,变换赋值给了src。此时src := scripts/kconfig。于是$(obj)和$(src)就相等,进入ifeq第一个分支里面。展开后,src还是等于scripts/kconfig,又进入下面一个ifeq里面,此时prefix赋值为'.'。这个src在以下命令里面继续处理:

# 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)

详细的展开过程就留给大家当个练习了。这里我们直接给结果,经过这样一个处理,现在有:

kbuild-dir := ./scripts/kconfig
kbuild-file := ./scripts/kconfig/Makefile
include ./scripts/kconfig/Makefile

于是,这里引入了另一个重要的Makefile。

经过搜索,你会发现,其实Makefile.build里面,其实是找不到menuconfig的匹配目标的,这个menuconfig匹配到了./scripts/kconfig/Makefile这个Makefile里面。我们打开看下,发现第36行有如下语句:

menuconfig: $(obj)/mconf
        $< $(silent) $(Kconfig)

menuconfig最终执行者

终于被我们找到这个鬼了。绕了一大圈,居然隐藏在这个鬼地方。而且这个规则极其简单,学过make的朋友都能分析出来这个规则干了些什么。这个规则只有一个依赖,那就是$(obj)/mconf,这个依赖的目标规则在哪里呢?我们找一找吧。

经过简单的字符串查找,我们发现,mconf在./scripts/kconfig/Makefile中的第190行,有这么个定义:

hostprogs-y := conf nconf mconf kxgettext qconf gconf

这里将mconf赋值给了hostprogs-y,具体hostprogs-y的规则,是在Makefile.host里面,为了不走偏本文主题,我们不详细展开,这里需要说明的是,mconf是一个本机程序,是通过本机gcc编译并在本机运行的。这个mconf是一个C语言程序,功能就是用来读取kconfig配置,然后生成图形配置界面,然后保存最终的配置文件。回到menuconfig规则,我们假设mconf已经准备好了,这个规则的命令展开如下:

$(obj)/mconf $(silent) $(Kconfig)

这里有个$(Kconfig)变量,我们看到./scripts/kconfig/Makefile第17行开始有这些赋值:

ifdef KBUILD_KCONFIG
Kconfig := $(KBUILD_KCONFIG)
else
Kconfig := Kconfig
endif

ifeq ($(quiet),silent_)
silent := -s
endif

所以,对于上述规则的命令,我们可以展开为:

$(obj)/mconf Kconfig

这个命令就是启动mconf程序,以Kconfig作为其输入。运行之后,就看到了那个漂亮的配置界面,然后,你就可以尽情去选择配置了。menuconfig路线我们梳理完毕。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值