配置Linux Kernel时make menuconfig执行流程分析
来源:互联网 发布:sketch软件 编辑:程序博客网 时间:2024/05/21 22:45
在编译内核前,一般是根据已有的配置文件(一般在内核根目录下的arch/arm/configs/文件夹下,把该目录下的xxx_defconfig文件拷贝到内核根目录下,并重命名为.config)来进行编译;或者需要先配置裁剪内核。
假设我们要基于一块ARM芯片的开发板配置裁剪内核时,在内核的根目录下运行:make ARCH=arm menuconfig命令后,会弹出如下配置界面:
当我们在内核的根目录下运行make ARM=arm menuconfig这条命令时,内核根目录下的Makefile是怎样被执行的呢?
回答这个问题之前,我们要先了解make这个工具的执行过程。GNU make找寻默认的Makefile规则是在当前目录下按顺序依次找三个文件 —“GNUmakefile”、“makefile”和“Makefile”,一旦找到就开始读取这个文件并执行。make menuconfig命令没有指定makefile文件,因此默认执行的是make –f Makefile menuconfig,即执行$(srctree)/Makefile文件中目标menuconfig的相关规则。一般来说,make的最终目标是makefile中的第一个目标,而其它目标一般是由这个目标连带出来的。这是make的默认行为。
如果你的makefile中的第一个目标是由许多个目标组成,你可以指示make,让其完成你所指定的目标。要达到这一目的很简单,需在make命令后直接跟目标的名字就可以完成(如make clean)。任何在makefile中的目标都可以被指定成终极目标,但是 除了以“-”打头,或是包含了“=”的目标,因为有这些字符的目标,会被解析成命令行参数或是变量。甚至没有被我们明确写出来的目标也可以成为make的终极目标,也就是说,只要make可以找到其隐含规则推导规则,那么这个隐含目标同样可以被指定成终极目标。
当在Linux内核(内核版本为3.18.42)顶层目录执行”make ARCH=arm menuconfig”时,命令行对内核根目录下Makefile文件的ARCH这个变量赋值为arm ,并且指定了make的目标是menuconfig。“menuconfig”这个目标在根目录下的Makefile中找到的匹配的目标是“%config”,因此会执行如下的规则:
%config: scripts_basic outputmakefile FORCE
上面的规则等价于:
menuconfig: scripts_basic outputmakefile FORCE
“menuconfig”这个目标有三个依赖:scripts_basic、outputmakefile、FORCE。先来分析下“menuconfig”这个目标下的命令:
1、$(Q)
看下变量Q在Makefile的定义:
# Beautify output
# ---------------------------------------------------------------------------
#
# Normally, we echo the whole command before executing it. By making
# that echo
# $(quiet) to choose other forms of output instead, e.g.
#
# quiet_cmd_cc_o_c = Compiling
# cmd_cc_o_c =
#
# If $(quiet) is empty, the whole command will be printed.
# If it is set to "quiet_", only the short version will be printed.
# If it is set to "silent_", nothing will be printed at all, since
# the variable $(silent_cmd_cc_o_c) doesn't exist.
#
# A simple variant is to prefix commands with $(Q) - that's useful
# for commands that shall be hidden in non-verbose mode.
#
#
#
# If KBUILD_VERBOSE equals 0 then the above command will be hidden.
# If KBUILD_VERBOSE equals 1 then the above command is displayed.
#
# To put more focus on warnings, be less verbose as default
# Use 'make V=1' to see the full commands
ifeq ("$(origin V)", "command line")
KBUILD_VERBOSE= $(V)
endif
ifndef KBUILD_VERBOSE
KBUILD_VERBOSE= 0
endif
ifeq ($(KBUILD_VERBOSE),1)
quiet=
Q=
else
quiet=quiet_
Q= @
endif
从上面的注释和Makefile语句可以看到,当在命令行传人V这个变量的值为1(V=1)时,就会使能quiet、Q变量的值为空,make在执行Makefile命令时就会向屏幕输出所执行的命令;当在命令行不传入V这个变量或者V的值为0(V=0)时,就会使能quiet=quiet_、Q= @,make在执行Makefile命令时就不会向屏幕输出所执行的命令。
2、$(MAKE)
MAKE是内嵌变量,其值为make。
3、$(build)
build这个变量是一个通用的变量,它定义在$(srctree)/scripts/Kbuild.include文件中:
###
# Shorthand for
# Usage:
#
build:= -f $(srctree)/scripts/Makefile.build obj
在内核的根目录下的Makefile包含了$(srctree)/scripts/Kbuild.include这个文件:
# We need some generic definitions (do not try to remake the file).
$(srctree)/scripts/Kbuild.include: ;
include$(srctree)/scripts/Kbuild.include
分析$(srctree)/scripts/Kbuild.include: ; 这条语句前我们先了解下make书写规则。规则的命令部分有两种书写方式:
a、目标、依赖描述和命令放在同一行,目标和依赖描述使用冒号(:)分隔开,在依赖文件列表后使用分号(;)把依赖文件列表和命令分开。
b、目标和依赖描述放在同一行,目标和依赖描述使用冒号(:)分隔开;命令行在目标、依赖描述的下一行。当作为独立的命令行时此行必须以[Tab]字符开始。在Makefile中,在第一个规则之后出现的所有以[Tab]字符开始的行都会被当作命令来处理。
$(srctree)/scripts/Kbuild.include: ; 这条语句使用的是第一种make书写规则,这条规则只有目标,没有依赖和命令。???因此make在执行这条规则的时候怎么执行???
include$(srctree)/scripts/Kbuild.include这条规则把$(srctree)/scripts/Kbuild.include这个文件包含到了内核根目录下的Makefile文件中。
从上面的分析可以知道build这个变量的值为-f$(srctree)/scripts/Makefile.build obj。
4、$@
$@是make的自动环变量,表示当前目标,即menuconfig。
下面来分析下scripts_basic、outputmakefile、FORCE这三个依赖:
1、FORCE
FORCE的定义为:
PHONY += FORCE
FORCE:
# Declare the contents of the .PHONY variable as phony. We keep that
# information in a variable so we can use it in if_changed and friends.
.PHONY:$(PHONY)
从上面看到,FORCE既没有依赖的规则,其底下也没有可执行的命令。如果一个规则没有命令或者依赖,并且它的目标不是一个存在的文件名。在执行此规则时,目标总会被认为是最新的。就是说:这个规则一旦被执行,make就认为它的目标已经被更新过。这样的目标在作为一个规则的依赖时,因为依赖总被认为被更新过,因此作为依赖所在的规则中定义的命令总会被执行。FORCE所在规则为空,也是什么都不做。FORCE被定义为一个伪目标,所以它作为依赖时总是被认为是最新的(比目标新),故有FORCE作为依赖的目标每次make时必然会重新生成,在这里FORCE伪目标的规则命令为空,故FORCE在Kbuild体系中,就是相当于是一个关键字,如果我们想要某个目标每次make的时候都一定会被重新生成,就把FORCE写为该目标的依赖。
2、scripts_basic
scripts_basic的定义为:
# Basic helpers built in scripts/
PHONY += scripts_basic
scripts_basic:
$(Q)rm -f .tmp_quiet_recordmcount
scripts_basic这个目标没有依赖,且scripts_basic也不是一个存在的文件,因此scripts_basic所定义的命令总会被执行。上述scripts_basic的定义等价为:
# Basic helpers built in scripts/
PHONY += scripts_basic
scripts_basic:
$(Q) make -f$(srctree)/scripts/Makefile.build obj=scripts/basic
$(Q)rm -f .tmp_quiet_recordmcount
$(Q) make -f $(srctree)/scripts/Makefile.build obj=scripts/basic这条命令指定了执行的是$(srctree)/scripts/Makefile.build这个Makefile,传递的参数是obj=scripts/basic。
接下来我们来分析下$(srctree)/scripts/Makefile.build这个Makefile文件。
obj这个变量传递进$(srctree)/scripts/Makefile.build中的src这个变量:
src:= $(obj)
即src := scripts/basic。
$(srctree)/scripts/Makefile.build把src (即scripts/basic)目录下的Makefile包含进来(如果有Kbuild则包含Kbuild)
# The filename Kbuild has precedence over Makefile
kbuild-dir:=
kbuild-file:=
include$(kbuild-file)
$(srctree)/scripts/Makefile.build也包含了scripts/Makefile.lib这个文件:
# If the save-* variables changed error out
ifeq ($(KBUILD_NOPEDANTIC),)
ifneq ("$(save-cflags)","$(CFLAGS)")
endif
endif
include scripts/Makefile.lib
在$(srctree)/scripts/Makefile.build这个Makefile文件中的第一个目标是:
__build:
$(subdir-ym)$(always)
@:
KBUILD_BUILTIN、KBUILD_MODULES在顶层Makefile中定义:
# Decide whether to build built-in, modular, or both.
# Normally, just do built-in.
KBUILD_MODULES:=
KBUILD_BUILTIN:= 1
# If we have only "make modules", don't compile built-in objects.
# When we're building modules with modversions, we need to consider
# the built-in objects during the descend as well, in order to
# make sure the checksums are up to date before we record them.
ifeq ($(MAKECMDGOALS),modules)
KBUILD_BUILTIN:=
endif
# If we have "make <whatever> modules", compile modules
# in addition to whatever we do anyway.
# Just "make" or "make all" shall build modules as well
ifneq (
KBUILD_MODULES:= 1
endif
ifeq ($(MAKECMDGOALS),)
KBUILD_MODULES:= 1
endif
export KBUILD_MODULES KBUILD_BUILTIN
export KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD
通过export关键字定义,使在makefile递归进行时,这两个变量被传递进子makefile。
这里:
KBUILD_MODULES:=
KBUILD_BUILTIN:= 1
KBUILD_BUILTIN和KBUILD_MODULES在顶层makefile文件中定义赋值后,就没有被改变过。所以此处__build目标的依赖就是
__build规则展开为:
__build:
@:
规则的命令是一个冒号命令”:”,冒号(:)命令是bash的内建命令,通常把它看作true命令。bash的help解释(help :)为:No effect; the command does nothing. A zero exit code is returned.(没有效果,该命令是空操作,退出状态总是0)。
__build的依赖除了$(always),
3、outputmakefile
outputmakefile在内核根目录下的Makefile中的定义为:
PHONY += outputmakefile
# outputmakefile generates a Makefile in the output directory, if using a
# separate output directory. This allows convenient use of make in the
# output directory.
outputmakefile:
ifneq ($(KBUILD_SRC),)
$(Q)ln -fsn$(srctree) source
$(srctree)$(objtree)$(VERSION)$(PATCHLEVEL)
endif
由于这里KBUILD_SRC为空,所以这个脚本并不会被执行。
到这里我们分析完了menuconfig的依赖,在处理完这些依赖后就开始执行规则的命令:把
$(Q) make -f $(srctree)/scripts/Makefile.build obj=scripts/kconfig menuconfig
这条命令指定要执行scripts/Makefile.build这个makefile文件。
在$(srctree)/scripts/Makefile.build中src变量的定义为:
src:= $(obj)
PHONY:= __build
__build:
# Init all relevant variables used in kbuild files so
# 1) they have correct type
# 2) they do not inherit any value from the environment
obj-y:=
obj-m:=
lib-y:=
lib-m:=
always:=
targets:=
subdir-y:=
subdir-m:=
EXTRA_AFLAGS :=
EXTRA_CFLAGS :=
EXTRA_CPPFLAGS:=
EXTRA_LDFLAGS :=
asflags-y :=
ccflags-y :=
cppflags-y:=
ldflags-y :=
subdir-asflags-y:=
subdir-ccflags-y:=
# Read auto.conf if it exists, otherwise ignore
-include include/config/auto.conf
include scripts/Kbuild.include
# For backward compatibility check that these variables do not change
save-cflags:= $(CFLAGS)
# The filename Kbuild has precedence over Makefile
kbuild-dir:=
kbuild-file:=
include$(kbuild-file)
由make -f scripts/Makefile.build obj=scripts/kconfig menuconfig可知,src值为scripts/kconfig,与/%的字串模式相符,因此
scripts/Makefile.build包含scripts/kconfig/Makefile文件(include $(kbuild-file))。目标menuconfig定义在scripts/kconfig/Makefile中,找到menuconfig目标后,然后执行以menuconfig为目标的规则:
PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config \
localmodconfig localyesconfig
ifdef KBUILD_KCONFIG
Kconfig:= $(KBUILD_KCONFIG)
else
Kconfig:= Kconfig
endif
# We need this, in case the user has it in its environment
unexport CONFIG_
... ...
menuconfig:$(obj)/mconf
$< $(Kconfig)
... ...
menuconfig目标的规则的命令是
NOTE:这里为什么说scripts/kconfig/mconf就是一个可执行文件呢?继续往下看scripts/kconfig/Makefile中的内容:
lxdialog:= lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o
lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
conf-objs := conf.o zconf.tab.o
mconf-objs := mconf.o zconf.tab.o $(lxdialog)
nconf-objs := nconf.o zconf.tab.o nconf.gui.o
kxgettext-objs := kxgettext.o zconf.tab.o
qconf-cxxobjs := qconf.o
qconf-objs := zconf.tab.o
gconf-objs := gconf.o zconf.tab.o
hostprogs-y:= conf nconf mconf kxgettext qconf gconf
clean-files:= qconf.moc .tmp_qtcheck .tmp_gtkcheck
clean-files += zconf.tab.c zconf.lex.c zconf.hash.c gconf.glade.h
clean-files += config.pot linux.pot
# Check that we have the required ncurses stuff installed for lxdialog (menuconfig)
PHONY +=$(obj)/dochecklxdialog
$(obj)/dochecklxdialog:
always:= dochecklxdialog
如果在编译内核的过程中,需要现编译出一些可执行文件供内核编译阶段使用,就需要借助Kbuild框架的本机程序支持的特性。Kbuild框架中,专门使用hostprogs-y变量来指示在内核编译阶段需要使用的一些可执行文件,通过hostprogs-y += mconf,就向make程序指明mconf是一个编译阶段需要使用的可执行文件。另外,Kbuild框架使用-objs后缀来指明相应的可执行文件需要通过多个目标文件来链接生成,mconf-objs := mconf.o zconf.tab.o $(lxdialog)就是向make指明,mconf文件是由mconf.o zconf.tab.o lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o链接生成的。再有,未明确写明生成规则时,Kbuild框架默认.o文件是由同名.c或.S文件编译生成的。我们在scripts\kconfig以及scripts\kconfig\lxdialog目录下可以找到前边8个.o文件的同名.c文件。
保存配置信息后会在内核根目录下生成一个.config文件,该文件保存了所做的内核配置信息。
- 配置Linux Kernel时make menuconfig执行流程分析
- linux kernel 配置 make menuconfig 执行流程分析
- make menuconfig 执行流程分析
- make menuconfig 执行流程分析
- make menuconfig 执行流程分析
- linux make menuconfig 执行流程小结
- linux make menuconfig 执行流程小结
- linux make menuconfig 执行流程小结
- linux make menuconfig 执行流程小结
- linux make menuconfig 执行流程小结
- linux make menuconfig 执行流程小结
- linux make menuconfig 执行流程小结
- linux make menuconfig 执行流程小结
- linux make menuconfig 执行流程小结
- Linux内核---6.make menuconfig 流程分析
- build linux kernel -- make menuconfig
- Linux kernel 分析之十五:kbuild系统-make menuconfig
- 如何用make menuconfig配置kernel
- Java奇淫巧技之Lombok
- 【JavaSE学习笔记】逻辑运算符
- basler、halcon在vs下的配置方法
- 7
- 傻瓜都能看懂的高并发量服务器架构
- 配置Linux Kernel时make menuconfig执行流程分析
- codeforces 813C The Tag Game
- oracle——expdp与impdp备份使用方法
- bootsrap学习笔记(一)<div>块如何水平居中
- 【持续更新】【cmd】cmd命令大全(2017年6月9日09:37:53)
- Retrofit+RxJava的联合使用
- Eclipse安装Svn无法连接问题
- Linux 下 fork, vfork,和clone的区别
- ECharts图表中修改每个category的颜色