(二)openwrt make kernel_menuconfig流程分析
2016-09-22 10:59
549 查看
(二)openwrt make kernel_menuconfig流程分析
在上一篇文章“(一)openwrt
make menuconfig流程分析”中,我们分析了make menuconfig的流程,在配置菜单中,我们并没有看到kernel相关的配置,这是因为在openwrt中,我们想要配置内核的话,需要使用make kernel_menuconfig命令。我们将通过分析这个命令执行的流程,看看它具体做了哪些工作。下面是我总结的分析过程,希望与大家分享,共同学习,共同成长,其中可能会有一些理解不正确的地方,还望各位不吝指教,谢谢,^_^。
当我们在顶层目录输入make kernel_menuconfig时,由于指定的目标为kernel_menuconfig,所以make会去寻找文件中kernel_menuconfig所在的地方,然后去执行其相应规则。同menuconfig目标一样,我们可以看到,kernel_menuconfig目标也在$(TOPDIR)/include/toplevel.mk中,下面是它的依赖和规则。其中$(TOPDIR)就是顶层目录,定义在主Makefile中TOPDIR:=${CURDIR}。
第1行,依赖目标prepare_kernel_conf的定义在$(TOPDIR)/include/toplevel.mk中:
下面对各依赖目标和规则进行分析。
.config定义在$(TOPDIR)/include/toplevel.mk中:
下面分析tmp/.prereq-build的依赖目标和规则。
1.1)第1~3行,tmp/.prereq-build依赖include/prereq-build.mk文件,创建tmp目录,删除tmp/.host.mk。
1.2)第4~7行,执行prereq-build.mk文件,用于检查一些必备条件是否准备好,例如下面列出的检查项,如果检查失败,则打印后面“Prerequisite check ...”信息。
2)第5~9行,继续来看简化一下如下:
make menuconfig流程分析”文章中scripts/config/mconf。CONFIG_HAVE_DOT_CONFIG变量的值为空,所以if条件不成立,得到prepare-tmpinfo依赖条件,该依赖条件的分析也在“(一)openwrt
make menuconfig流程分析”文章中有讲到。
第6~9行,这里的规则只有一个if条件语句,其表示如果顶层目录下不存在.config文件,或存在.config,但是该文件中没找到CONFIG_HAVE_DOT_CONFIG,则if条件成立,那将会执行make menuconfig命令;否则该规则什么也不做。
依赖目标FORCE在“(一)openwrt
make menuconfig流程分析”文章中有分析,这里不再分析了。
第3~8行,表示若staging_dir/host/bin/quilt工具不存在,即ifeq条件成立,则执行下面命令,生成该工具,否则执行else部分,即什么都不做。quilt是一个帮助我们管理patch的工具。
(1)检查一些必备条件是否准备好,比如gawk、zlib、getopt、openssl等,
(2)根据顶层目录下是否存在.config文件,以及该文件中是否有CONFIG_HAVE_DOT_CONFIG,决定要不要执行make menuconfig命令。
第2行,kernel_menuconfig的依赖目标分析完后,我们再看一下它的规则,将其简化一下:
上面规则中BOARD变量定义在$(TOPDIR)/include/rules.mk文件中,如下所示,rules.mk是由上面的$(TOPDIR)/target/linux/Makefile读入的。
第4行,定义了一个qstrip变量,其含义为去掉$(1)参数中的 “双引号,以及多余的空格或tab。
第5行,是注释,我的理解是,它对实际语法的正确性没有影响,由于第4行出现了单个双引号,增加这行,可以避免影响第4行之后命令的显示。
第6行,从CONFIG_TARGET_BOARD变量获取值,我这里获取的值为ramips。
接下来继续来分析$(TOPDIR)/target/linux/ramips/Makefile,该文件中核心代码如下,其他部分代码定义的是一些公共变量,我们在用到的时候再去分析:
BuildKernel定义在$(TOPDIR)/include/kernel-build.mk中,这个变量中定义的目标和规则较多,我们直接看要执行的menuconfig目标的规则:
第3行,menuconfig依赖.prepared、.quilt_checked这两个依赖目标,它们是内核顶层目录下的两个文件。当这两个目标文件不存在时,他们对应的规则就会被执行,我们依次来分析这俩目标。
1)依赖目标.prepared
.prepared定义在$(TOPDIR)/include/kernel-build.mk中
1.1).prepared的依赖目标
第1行,LINUX_SITE定义在$(TOPDIR)/include/kernel.mk中,CONFIG_EXTERNAL_KERNEL_TREE、CONFIG_KERNEL_GIT_CLONE_URI在顶层.config中都为"",LINUX_VERSION值为3.10.14。
DL_DIR定义在$(TOPDIR)/rules.mk中,CONFIG_DOWNLOAD_FOLDER在顶层.config中为"",所以$(DL_DIR)值为$(TOPDIR)/dl。
1.2).prepared的规则
第2、3行,KERNEL_BUILD_DIR定义在$(TOPDIR)/include/kernel.mk中,BOARD值为ramips,SUBTARGET值为mt7628。
所以,这两行规则是删除linux-ramips_mt7628目录,再重新创建。
第4行,Kernel/Prepare定义在$(TOPDIR)/include/kernel-build.mk中
Kernel/Prepare/Default定义在$(TOPDIR)/include/kernel-defaults.mk中
第5行,准备工作完成后,创建.prepared文件。
2)依赖目标.quilt_checked
.quilt_checked的规则定义在$(TOPDIR)/include/quilt.mk中,它是由BuildKernel变量中$(if
$(QUILT),$(Build/Quilt))这行命令展开的,QUILT值为1。
$(1)值为$(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14,$(2)值为空,因为if中series文件不存在,所以if条件不成立,.quilt_checked的规则只是创建了一个.quilt_checked这个文件。
第4行,删除内核顶层目录中的.configured文件。
第5行,这行规则不复杂,但是变量的定义比较繁琐,我们依次分析LINUX_RECONF_CMD、LINUX_DIR变量的值,最后再看这行规则的作用。
1)LINUX_RECONF_CMD变量
LINUX_RECONF_CMD定义在$(TOPDIR)/include/target.mk中:
1.1)__linux_confcmd变量
__linux_confcmd定义在$(TOPDIR)/include/target.mk中:
LINUX_RECONFIG_LIST定义在$(TOPDIR)/include/target.mk中:
1.2.1)GENERIC_LINUX_CONFIG变量
GENERIC_LINUX_CONFIG定义在$(TOPDIR)/include/target.mk中:
因此,由上面命令,可以知道GENERIC_LINUX_CONFIG变量后面的命令表示,在$(TOPDIR)/target/linux/generic目录中为GENERIC_LINUX_CONFIG变量寻找config-3.10或config-default配置文件,如两个都有,则优先赋值config-3.10,如只有config-default,则赋值此文件,如都没有,则默认赋值config-default。由于$(TOPDIR)/target/linux/generic目录中有config-3.10文件,所以在这里赋值的是$(TOPDIR)/target/linux/generic/config-3.10。
1.2.2)LINUX_TARGET_CONFIG变量
LINUX_TARGET_CONFIG定义在$(TOPDIR)/include/target.mk中,BOARD变量值为ramips,前面有分析。
1.2.3)USE_SUBTARGET_CONFIG和LINUX_SUBTARGET_CONFIG变量
USE_SUBTARGET_CONFIG、LINUX_SUBTARGET_CONFIG定义在$(TOPDIR)/include/target.mk中,SUBTARGET变量值为mt7628。
上面命令中,PLATFORM_DIR的值由1.2.2)可得到,PLATFORM_SUBDIR的值为$(TOPDIR)/target/linux/ramips/mt7628,所以这两个变量不相等,ifneq条件成立,从而可知LINUX_SUBTARGET_CONFIG变量值为$(TOPDIR)/target/linux/ramips/mt7628/config-3.10。USE_SUBTARGET_CONFIG变量的为1。
2)LINUX_DIR变量
LINUX_DIR定义在$(TOPDIR)/include/kernel.mk中,BOARD值为ramips,SUBTARGET值为mt7628,LINUX_VERSION值为3.10.14。
3)合并config文件为.config
通过1)、2)的分析,我们知道了LINUX_RECONF_CMD、LINUX_DIR变量的值,此时,我们可将第5行规则简化如下:
这行规则作用是通过kconfig.pl脚本将两个config-3.10文件合并为内核顶层目录下的.config文件。
第6行,make命令进入到内核顶层目录下,并在该目录下Makefile中寻找menuconfig目标,然后执行其对应规则,最主要的是会执行内核scripts目录中mconf可执行文件。mconf会解析内核顶层目录下Kconfig、.config文件,并绘制图形界面供我们进行相关选项的配置。然后在我们保存退出时,.config就会被及时的更新。
第7行,先分析一下LINUX_RECONF_DIFF,LINUX_RECONFIG_TARGET这两个变量,再分析这行规则的作用。
1)LINUX_RECONF_DIFF变量
LINUX_RECONF_DIFF定义在$(TOPDIR)/include/target.mk中,__linux_confcmd在2.2.3的1.1)中可得到,LINUX_RECONFIG_LIST在2.2.3的1.2)中可得到。
1.1)LINUX_RECONFIG_TARGET变量
LINUX_RECONFIG_TARGET定义在$(TOPDIR)/include/target.mk中。
的1.2.3)中得到,所以LINUX_RECONFIG_TARGET变量值为$(TOPDIR)/target/linux/ramips/mt7628/config-3.10。
2)更新config文件
可将第7行命令简化如下:
而这行规则作用是通过kconfig.pl脚本将更新过的.config文件,去掉$(TOPDIR)/target/linux/generic/config-3.10中的配置,得到已更新的$(TOPDIR)/target/linux/ramips/mt7628/config-3.10文件,然后重新写回到$(TOPDIR)/target/linux/ramips/mt7628/config-3.10文件。也就是说,当我们在内核中更改了配置更新了.config后,需要把mt7628的config-3.10文件也对应的更新了。
(1)将内核源码从$(TOPDIR)/target/linux/src/linux-3.10.14目录拷贝到$(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628目录,等待make命令去build_dir目录中编译内核。内核源码也可以是从网上进行下载解压得到,这个过程我还未去了解,之后再找时间去看一看。
(2)将$(TOPDIR)/target/linux/generic/config-3.10、$(TOPDIR)/target/linux/ramips/mt7628/config-3.10这两个配置文件合并到编译目录$(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14/.config中。
(3)启动内核图形配置界面,对内核进行配置,完成后更新内核顶层目录的.config文件,并由该文件更新target目录中mt7628的config-3.10文件。
(2)一些变量的定义比较繁琐,在分析的时候比较花时间。
(3)文中有个别地方,我目前理解的可能不太准确,希望有人能给予指出。或我知道了之后,再来更新,谢谢。
在上一篇文章“(一)openwrt
make menuconfig流程分析”中,我们分析了make menuconfig的流程,在配置菜单中,我们并没有看到kernel相关的配置,这是因为在openwrt中,我们想要配置内核的话,需要使用make kernel_menuconfig命令。我们将通过分析这个命令执行的流程,看看它具体做了哪些工作。下面是我总结的分析过程,希望与大家分享,共同学习,共同成长,其中可能会有一些理解不正确的地方,还望各位不吝指教,谢谢,^_^。
当我们在顶层目录输入make kernel_menuconfig时,由于指定的目标为kernel_menuconfig,所以make会去寻找文件中kernel_menuconfig所在的地方,然后去执行其相应规则。同menuconfig目标一样,我们可以看到,kernel_menuconfig目标也在$(TOPDIR)/include/toplevel.mk中,下面是它的依赖和规则。其中$(TOPDIR)就是顶层目录,定义在主Makefile中TOPDIR:=${CURDIR}。
kernel_menuconfig: prepare_kernel_conf $(_SINGLE)$(NO_TRACE_MAKE) -C target/linux menuconfig
1 kernel_menuconfig的依赖目标prepare_kernel_conf
第1行,依赖目标prepare_kernel_conf的定义在$(TOPDIR)/include/toplevel.mk中:prepare_kernel_conf: .config FORCE ifeq ($(wildcard staging_dir/host/bin/quilt),) prepare_kernel_conf: @+$(SUBMAKE) -r tools/quilt/install else prepare_kernel_conf: ; endif
下面对各依赖目标和规则进行分析。
1.1 prepare_kernel_conf的依赖目标.config
.config定义在$(TOPDIR)/include/toplevel.mk中:ifeq ($(FORCE),) .config scripts/config/conf scripts/config/mconf: tmp/.prereq-build endif .config: ./scripts/config/conf $(if $(CONFIG_HAVE_DOT_CONFIG),,prepare-tmpinfo) @+if [ \! -e .config ] || ! grep CONFIG_HAVE_DOT_CONFIG .config >/dev/null; then \ [ -e $(HOME)/.openwrt/defconfig ] && cp $(HOME)/.openwrt/defconfig .config; \ $(_SINGLE)$(NO_TRACE_MAKE) menuconfig $(PREP_MK); \ fi1)第1~3行,默认FORCE是等于空的,所以这里的if条件成立,即.config依赖于tmp/.prereq-build,我们看一下tmp/.prereq-build的定义:
tmp/.prereq-build: include/prereq-build.mk mkdir -p tmp rm -f tmp/.host.mk @$(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -f $(TOPDIR)/include/prereq-build.mk prereq 2>/dev/null || { \ echo "Prerequisite check failed. Use FORCE=1 to override."; \ false; \ } touch $@
下面分析tmp/.prereq-build的依赖目标和规则。
1.1)第1~3行,tmp/.prereq-build依赖include/prereq-build.mk文件,创建tmp目录,删除tmp/.host.mk。
1.2)第4~7行,执行prereq-build.mk文件,用于检查一些必备条件是否准备好,例如下面列出的检查项,如果检查失败,则打印后面“Prerequisite check ...”信息。
Checking 'working-make'... ok. Checking 'case-sensitive-fs'... ok. Checking 'getopt'... ok. Checking 'fileutils'... ok. Checking 'working-gcc'... ok. ...1.3)第8行,检查完后,创建tmp/.prereq-build文件。
2)第5~9行,继续来看简化一下如下:
.config: ./scripts/config/conf prepare-tmpinfo @+if [ \! -e .config ] || ! grep CONFIG_HAVE_DOT_CONFIG .config >/dev/null; then \ [ -e $(HOME)/.openwrt/defconfig ] && cp $(HOME)/.openwrt/defconfig .config; \ make menuconfig; \ fi第5行,./scripts/config/conf依赖目标的分析可参考“(一)openwrt
make menuconfig流程分析”文章中scripts/config/mconf。CONFIG_HAVE_DOT_CONFIG变量的值为空,所以if条件不成立,得到prepare-tmpinfo依赖条件,该依赖条件的分析也在“(一)openwrt
make menuconfig流程分析”文章中有讲到。
第6~9行,这里的规则只有一个if条件语句,其表示如果顶层目录下不存在.config文件,或存在.config,但是该文件中没找到CONFIG_HAVE_DOT_CONFIG,则if条件成立,那将会执行make menuconfig命令;否则该规则什么也不做。
1.2 prepare_kernel_conf的依赖目标FORCE
依赖目标FORCE在“(一)openwrtmake menuconfig流程分析”文章中有分析,这里不再分析了。
1.3 prepare_kernel_conf的规则
第3~8行,表示若staging_dir/host/bin/quilt工具不存在,即ifeq条件成立,则执行下面命令,生成该工具,否则执行else部分,即什么都不做。quilt是一个帮助我们管理patch的工具。@+$(SUBMAKE) -r tools/quilt/install
1.4 小结
kernel_menuconfig的依赖目标prepare_kernel_conf主要做的工作是:(1)检查一些必备条件是否准备好,比如gawk、zlib、getopt、openssl等,
(2)根据顶层目录下是否存在.config文件,以及该文件中是否有CONFIG_HAVE_DOT_CONFIG,决定要不要执行make menuconfig命令。
2 kernel_menuconfig的规则
第2行,kernel_menuconfig的依赖目标分析完后,我们再看一下它的规则,将其简化一下:make -C target/linux menuconfig可以看到,这行规则表示要去执行$(TOPDIR)/target/linux目录下Makefile,目标是menuconfig。继续看一下此Makefile中menuconfig目标的定义:
prereq clean download prepare compile install menuconfig nconfig oldconfig update refresh: FORCE @+$(NO_TRACE_MAKE) -C $(BOARD) $@将其简化一下,如下,menuconfig的规则表示要进入$(TOPDIR)/target/linux/ramips目录,去执行里面的Makefile,目标为menuconfig。
menuconfig: FORCE @+make -C ramips menuconfig下面分析一下BOARD变量如何得到的,以及在$(TOPDIR)/target/linux/ramips/Makefile中执行的规则。
2.1 BOARD变量
上面规则中BOARD变量定义在$(TOPDIR)/include/rules.mk文件中,如下所示,rules.mk是由上面的$(TOPDIR)/target/linux/Makefile读入的。ifeq ($(DUMP),) -include $(TOPDIR)/.config endif qstrip=$(strip $(subst ",,$(1))) #")) BOARD:=$(call qstrip,$(CONFIG_TARGET_BOARD))第1~3行,表示读取顶层目录中的.config文件,它包含了CONFIG_TARGET_BOARD=“ramips”变量的值。
第4行,定义了一个qstrip变量,其含义为去掉$(1)参数中的 “双引号,以及多余的空格或tab。
第5行,是注释,我的理解是,它对实际语法的正确性没有影响,由于第4行出现了单个双引号,增加这行,可以避免影响第4行之后命令的显示。
第6行,从CONFIG_TARGET_BOARD变量获取值,我这里获取的值为ramips。
2.2 ramips的目标和规则
接下来继续来分析$(TOPDIR)/target/linux/ramips/Makefile,该文件中核心代码如下,其他部分代码定义的是一些公共变量,我们在用到的时候再去分析:$(eval $(call BuildTarget))根据该代码可知,这里调用了BuildTarget变量,BuildTarget定义在$(TOPDIR)/include/target.mk中,如下:
ifeq ($(TARGET_BUILD),1) include $( 14e84 INCLUDE_DIR)/kernel-build.mk BuildTarget?=$(BuildKernel) endifTARGET_BUILD变量的值在$(TOPDIR)/target/linux/Makefile中定义为1,所以if条件成立,因此BuildTarget的值为BuildKernel变量的值。
BuildKernel定义在$(TOPDIR)/include/kernel-build.mk中,这个变量中定义的目标和规则较多,我们直接看要执行的menuconfig目标的规则:
define BuildKernel ... oldconfig menuconfig nconfig: $(STAMP_PREPARED) $(STAMP_CHECKED) FORCE rm -f $(STAMP_CONFIGURED) $(LINUX_RECONF_CMD) > $(LINUX_DIR)/.config $(_SINGLE)$(MAKE) -C $(LINUX_DIR) $(KERNEL_MAKEOPTS) $$@ $(LINUX_RECONF_DIFF) $(LINUX_DIR)/.config > $(LINUX_RECONFIG_TARGET) ... endef我们将其简化一下如下。
define BuildKernel ... menuconfig: $(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14/.prepared $(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14/.quilt_checked FORCE rm -f $(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14/.configured $(LINUX_RECONF_CMD) > $(LINUX_DIR)/.config make -C build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14 menuconfig $(LINUX_RECONF_DIFF) $(TOPDIR)/.config > $(LINUX_RECONFIG_TARGET) ... endef下面详细分析这些目标和规则。
2.2.1 内核menuconfig的依赖目标
第3行,menuconfig依赖.prepared、.quilt_checked这两个依赖目标,它们是内核顶层目录下的两个文件。当这两个目标文件不存在时,他们对应的规则就会被执行,我们依次来分析这俩目标。1)依赖目标.prepared
.prepared定义在$(TOPDIR)/include/kernel-build.mk中
$(STAMP_PREPARED): $(if $(LINUX_SITE),$(DL_DIR)/$(LINUX_SOURCE)) -rm -rf $(KERNEL_BUILD_DIR) -mkdir -p $(KERNEL_BUILD_DIR) $(Kernel/Prepare) touch $$@
1.1).prepared的依赖目标
第1行,LINUX_SITE定义在$(TOPDIR)/include/kernel.mk中,CONFIG_EXTERNAL_KERNEL_TREE、CONFIG_KERNEL_GIT_CLONE_URI在顶层.config中都为"",LINUX_VERSION值为3.10.14。
TESTING:=$(if $(findstring -rc,$(LINUX_VERSION)),/testing,) ifeq ($(call qstrip,$(CONFIG_EXTERNAL_KERNEL_TREE))$(call qstrip,$(CONFIG_KERNEL_GIT_CLONE_URI)),) LINUX_SITE:=@KERNEL/linux/kernel/v3.x$(TESTING) endif所以ifeq条件成立,LINUX_SITE值为@KERNEL/linux/kernel/v3.x,则.prepared的依赖目标为$(DL_DIR)/$(LINUX_SOURCE)。
DL_DIR定义在$(TOPDIR)/rules.mk中,CONFIG_DOWNLOAD_FOLDER在顶层.config中为"",所以$(DL_DIR)值为$(TOPDIR)/dl。
DL_DIR:=$(if $(call qstrip,$(CONFIG_DOWNLOAD_FOLDER)),$(call qstrip,$(CONFIG_DOWNLOAD_FOLDER)),$(TOPDIR)/dl)LINUX_SOURCE定义在$(TOPDIR)/include/kernel.mk中
LINUX_SOURCE:=linux-$(LINUX_VERSION).tar.xz由此可知,.prepared的依赖目标即为$(TOPDIR)/dl/linux-3.10.14.tar.xz
1.2).prepared的规则
第2、3行,KERNEL_BUILD_DIR定义在$(TOPDIR)/include/kernel.mk中,BOARD值为ramips,SUBTARGET值为mt7628。
KERNEL_BUILD_DIR ?= $(BUILD_DIR)/linux-$(BOARD)$(if $(SUBTARGET),_$(SUBTARGET))BUILD_DIR定义在$(TOPDIR)/rules.mk中,TARGET_DIR_NAME值为target-mipsel_24kec+dsp_uClibc-0.9.33.2。
BUILD_DIR_BASE:=$(TOPDIR)/build_dir BUILD_DIR:=$(BUILD_DIR_BASE)/$(TARGET_DIR_NAME)最终可得到KERNEL_BUILD_DIR值为:
$(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628
所以,这两行规则是删除linux-ramips_mt7628目录,再重新创建。
第4行,Kernel/Prepare定义在$(TOPDIR)/include/kernel-build.mk中
define Kernel/Prepare $(call Kernel/Prepare/Default) endef
Kernel/Prepare/Default定义在$(TOPDIR)/include/kernel-defaults.mk中
ifeq ($(strip $(CONFIG_EXTERNAL_KERNEL_TREE)),"") ifeq ($(strip $(CONFIG_KERNEL_GIT_CLONE_URI)),"") define Kernel/Prepare/Default $(CP) $(TOPDIR)/target/linux/src/linux-$(LINUX_VERSION) $(KERNEL_BUILD_DIR) ln -sf $(LINUX_DIR) `echo $(LINUX_DIR) | sed 's/linux-[0-9]*\.[0-9]*\.[0-9]*/linux-kernel/g'` endef else define Kernel/Prepare/Default ... endef endif else define Kernel/Prepare/Default ... endef endif两个ifeq都成立,所以使用第一个Kernel/Prepare/Default变量,将其简化一下,LINUX_VERSION值在后面的2.2.3的2)有分析。
cp -fpR $(TOPDIR)/target/linux/src/linux-3.10.14 $(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628 ln -sf $(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14 $(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-kernel因此可知道,第4行所做工作就是从target目录拷贝内核源码linux-3.10.14到build_dir目录中,并为内核源码创建软链接linux-kernel。
第5行,准备工作完成后,创建.prepared文件。
2)依赖目标.quilt_checked
.quilt_checked的规则定义在$(TOPDIR)/include/quilt.mk中,它是由BuildKernel变量中$(if
$(QUILT),$(Build/Quilt))这行命令展开的,QUILT值为1。
$(1)值为$(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14,$(2)值为空,因为if中series文件不存在,所以if条件不成立,.quilt_checked的规则只是创建了一个.quilt_checked这个文件。
define Quilt/Template ... $($(2)STAMP_CHECKED): $($(2)STAMP_PREPARED) if [ -s "$(1)/patches/series" ]; then \ (cd "$(1)"; \ if $(QUILT_CMD) next >/dev/null 2>&1; then \ $(QUILT_CMD) push -a; \ else \ $(QUILT_CMD) top >/dev/null 2>&1; \ fi \ ); \ fi touch "$$@" ... endef Build/Quilt=$(call Quilt/Template,$(PKG_BUILD_DIR),,,$(if $(TARGET_BUILD),Kernel,Package))
2.2.2 删除内核的.configured文件
第4行,删除内核顶层目录中的.configured文件。
2.2.3 内核.config的生成
第5行,这行规则不复杂,但是变量的定义比较繁琐,我们依次分析LINUX_RECONF_CMD、LINUX_DIR变量的值,最后再看这行规则的作用。1)LINUX_RECONF_CMD变量
LINUX_RECONF_CMD定义在$(TOPDIR)/include/target.mk中:
LINUX_RECONF_CMD = $(call __linux_confcmd,$(LINUX_RECONFIG_LIST),)
1.1)__linux_confcmd变量
__linux_confcmd定义在$(TOPDIR)/include/target.mk中:
__linux_confcmd = $(SCRIPT_DIR)/kconfig.pl $(2) $(patsubst %,+,$(wordlist 2,9999,$(1))) $(1)1.2)LINUX_RECONFIG_LIST变量
LINUX_RECONFIG_LIST定义在$(TOPDIR)/include/target.mk中:
LINUX_RECONFIG_LIST = $(wildcard $(GENERIC_LINUX_CONFIG) $(LINUX_TARGET_CONFIG) $(if $(USE_SUBTARGET_CONFIG), $(LINUX_SUBTARGET_CONFIG)))通过这行命令,最终可得到LINUX_RECONFIG_LIST的值为:
LINUX_RECONFIG_LIST = $(TOPDIR)/target/linux/generic/config-3.10 $(TOPDIR)/target/linux/ramips/mt7628/config-3.10下面分析 LINUX_RECONFIG_LIST的这行命令。
1.2.1)GENERIC_LINUX_CONFIG变量
GENERIC_LINUX_CONFIG定义在$(TOPDIR)/include/target.mk中:
GENERIC_LINUX_CONFIG = $(call find_kernel_config,$(GENERIC_PLATFORM_DIR))其中,find_kernel_config、GENERIC_PLATFORM_DIR变量定义在$(TOPDIR)/include/target.mk中,KERNEL_PATCHVER变量定义在$(TOPDIR)/include/kernel-version.mk中,为3.10。
__config_name_list = $(1)/config-$(KERNEL_PATCHVER) $(1)/config-default __config_list = $(firstword $(wildcard $(call __config_name_list,$(1)))) find_kernel_config=$(if $(__config_list),$(__config_list),$(lastword $(__config_name_list))) GENERIC_PLATFORM_DIR := $(TOPDIR)/target/linux/generic
因此,由上面命令,可以知道GENERIC_LINUX_CONFIG变量后面的命令表示,在$(TOPDIR)/target/linux/generic目录中为GENERIC_LINUX_CONFIG变量寻找config-3.10或config-default配置文件,如两个都有,则优先赋值config-3.10,如只有config-default,则赋值此文件,如都没有,则默认赋值config-default。由于$(TOPDIR)/target/linux/generic目录中有config-3.10文件,所以在这里赋值的是$(TOPDIR)/target/linux/generic/config-3.10。
1.2.2)LINUX_TARGET_CONFIG变量
LINUX_TARGET_CONFIG定义在$(TOPDIR)/include/target.mk中,BOARD变量值为ramips,前面有分析。
PLATFORM_DIR:=$(TOPDIR)/target/linux/$(BOARD) LINUX_TARGET_CONFIG = $(call find_kernel_config,$(PLATFORM_DIR))LINUX_TARGET_CONFIG变量后面的命令表示的含义与GENERIC_LINUX_CONFIG类似。由于$(TOPDIR)/target/linux/ramips/目录中无config-3.10、config-default文件,所以在这里赋值的是$(TOPDIR)/target/linux/ramips/config-default。
1.2.3)USE_SUBTARGET_CONFIG和LINUX_SUBTARGET_CONFIG变量
USE_SUBTARGET_CONFIG、LINUX_SUBTARGET_CONFIG定义在$(TOPDIR)/include/target.mk中,SUBTARGET变量值为mt7628。
PLATFORM_SUBDIR:=$(PLATFORM_DIR)$(if $(SUBTARGET),/$(SUBTARGET)) ifneq ($(PLATFORM_DIR),$(PLATFORM_SUBDIR)) LINUX_SUBTARGET_CONFIG = $(call find_kernel_config,$(PLATFORM_SUBDIR)) endif USE_SUBTARGET_CONFIG = $(if $(wildcard $(LINUX_TARGET_CONFIG)),,$(if $(LINUX_SUBTARGET_CONFIG),1))
上面命令中,PLATFORM_DIR的值由1.2.2)可得到,PLATFORM_SUBDIR的值为$(TOPDIR)/target/linux/ramips/mt7628,所以这两个变量不相等,ifneq条件成立,从而可知LINUX_SUBTARGET_CONFIG变量值为$(TOPDIR)/target/linux/ramips/mt7628/config-3.10。USE_SUBTARGET_CONFIG变量的为1。
2)LINUX_DIR变量
LINUX_DIR定义在$(TOPDIR)/include/kernel.mk中,BOARD值为ramips,SUBTARGET值为mt7628,LINUX_VERSION值为3.10.14。
KERNEL_BUILD_DIR ?= $(BUILD_DIR)/linux-$(BOARD)$(if $(SUBTARGET),_$(SUBTARGET)) LINUX_DIR ?= $(KERNEL_BUILD_DIR)/linux-$(LINUX_VERSION)BUILD_DIR定义在$(TOPDIR)/rules.mk中,TARGET_DIR_NAME值为target-mipsel_24kec+dsp_uClibc-0.9.33.2。
BUILD_DIR_BASE:=$(TOPDIR)/build_dir BUILD_DIR:=$(BUILD_DIR_BASE)/$(TARGET_DIR_NAME)最终可得到LINUX_DIR值为:
$(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14
3)合并config文件为.config
通过1)、2)的分析,我们知道了LINUX_RECONF_CMD、LINUX_DIR变量的值,此时,我们可将第5行规则简化如下:
$(TOPDIR)/scripts/kconfig.pl + $(TOPDIR)/target/linux/generic/config-3.10 $(TOPDIR)/target/linux/ramips/mt7628/config-3.10 > $(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14/.config
这行规则作用是通过kconfig.pl脚本将两个config-3.10文件合并为内核顶层目录下的.config文件。
2.2.4 生成内核图形界面配置内核
第6行,make命令进入到内核顶层目录下,并在该目录下Makefile中寻找menuconfig目标,然后执行其对应规则,最主要的是会执行内核scripts目录中mconf可执行文件。mconf会解析内核顶层目录下Kconfig、.config文件,并绘制图形界面供我们进行相关选项的配置。然后在我们保存退出时,.config就会被及时的更新。
2.2.5 更新mt7628的config-3.10文件
第7行,先分析一下LINUX_RECONF_DIFF,LINUX_RECONFIG_TARGET这两个变量,再分析这行规则的作用。1)LINUX_RECONF_DIFF变量
LINUX_RECONF_DIFF定义在$(TOPDIR)/include/target.mk中,__linux_confcmd在2.2.3的1.1)中可得到,LINUX_RECONFIG_LIST在2.2.3的1.2)中可得到。
LINUX_RECONF_DIFF = $(call __linux_confcmd,$(filter-out $(LINUX_RECONFIG_TARGET),$(LINUX_RECONFIG_LIST)),'>')
1.1)LINUX_RECONFIG_TARGET变量
LINUX_RECONFIG_TARGET定义在$(TOPDIR)/include/target.mk中。
LINUX_RECONFIG_TARGET = $(if $(USE_SUBTARGET_CONFIG),$(LINUX_SUBTARGET_CONFIG),$(LINUX_TARGET_CONFIG))USE_SUBTARGET_CONFIG,LINUX_SUBTARGET_CONFIG在2.2.3
的1.2.3)中得到,所以LINUX_RECONFIG_TARGET变量值为$(TOPDIR)/target/linux/ramips/mt7628/config-3.10。
2)更新config文件
可将第7行命令简化如下:
$(TOPDIR)/scripts/kconfig.pl ‘>’ $(TOPDIR)/target/linux/generic/config-3.10 $(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14/.config > $(TOPDIR)/target/linux/ramips/mt7628/config-3.10我们知道内核顶层目录中的.config文件是由两个config-3.10文件合并得到的,在我们配置了内核后,.config文件将被更新。
而这行规则作用是通过kconfig.pl脚本将更新过的.config文件,去掉$(TOPDIR)/target/linux/generic/config-3.10中的配置,得到已更新的$(TOPDIR)/target/linux/ramips/mt7628/config-3.10文件,然后重新写回到$(TOPDIR)/target/linux/ramips/mt7628/config-3.10文件。也就是说,当我们在内核中更改了配置更新了.config后,需要把mt7628的config-3.10文件也对应的更新了。
2.3 小结
kernel_menuconfig的规则主要做的工作是:(1)将内核源码从$(TOPDIR)/target/linux/src/linux-3.10.14目录拷贝到$(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628目录,等待make命令去build_dir目录中编译内核。内核源码也可以是从网上进行下载解压得到,这个过程我还未去了解,之后再找时间去看一看。
(2)将$(TOPDIR)/target/linux/generic/config-3.10、$(TOPDIR)/target/linux/ramips/mt7628/config-3.10这两个配置文件合并到编译目录$(TOPDIR)/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14/.config中。
(3)启动内核图形配置界面,对内核进行配置,完成后更新内核顶层目录的.config文件,并由该文件更新target目录中mt7628的config-3.10文件。
3 总结
(1)在分析内核的配置流程后,我们可以发现整个流程其实是比较简单的,大致的主要过程是复制内核到编译目录,合并生成一个.config文件,然后进行内核配置并更新.config,最后更新mt7628的config-3.10。(2)一些变量的定义比较繁琐,在分析的时候比较花时间。
(3)文中有个别地方,我目前理解的可能不太准确,希望有人能给予指出。或我知道了之后,再来更新,谢谢。
相关文章推荐
- (二)openwrt make kernel_menuconfig流程分析
- (二)openwrt make kernel_menuconfig流程分析
- (二)openwrt make kernel_menuconfig流程分析
- (二)openwrt make kernel_menuconfig流程分析
- (二)openwrt make kernel_menuconfig流程分析
- (一)openwrt make menuconfig流程分析
- (一)openwrt make menuconfig流程分析
- (一)openwrt make menuconfig流程分析
- (一)openwrt make menuconfig流程分析
- (一)openwrt make menuconfig流程分析
- (一)openwrt make menuconfig流程分析
- OPENWRT make menuconfig错误之一
- make menuconfig 执行流程分析
- make kernel MENUCONFIG=1
- Make ARCH=arm CROSS_COMPILE=arm-linux-gcc menuconfig 分析
- linux make menuconfig 执行流程小结
- OPENWRT make defconfig错误之一
- Linux kernel make menuconfig 时出错处理方法
- Linux kernel 分析之十五:kbuild系统-make menuconfig