Linux Kernel Makefile解析(一)

本文转自https://blog.csdn.net/dreamflyliwei9/article/details/51379021

编译内核首先要执行make menuconfig,那我们就从这条命令开始。(P.S. 内核版本 3.8.0)

1. Makefile变量的初始化

KBUILD_EXTMOD 为空,因为命令行中没有”M= xxx“,KBUILD_SRC为空,因为没有“O = xxx“。


no-dot-config-targets := clean mrproper distclean \
             cscope gtags TAGS tags help %docs check% coccicheck \
             $(version_h) headers_% archheaders archscripts \
            no-dot-config-targets kernelversion %src-pkg

config-targets := 0
mixed-targets  := 0
dot-config     := 1

ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
    ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
        # MAKECMDGOALS 中仅包含no-dot-config-targets提供的命令
        dot-config := 0
    endif
endif

ifeq ($(KBUILD_EXTMOD),)
        ifneq ($(filter config %config,$(MAKECMDGOALS)),)
        # MAKECMDGOALS 包含config
                config-targets := 1
                ifneq ($(filter-out config %config,$(MAKECMDGOALS)),)
                # MAKECMDGOALS 还包含其他命令
                        mixed-targets := 1
                endif

endif

由上面代码可以得出如下几个变量的值: 
config-targets = 1 
mixed-targets = 0 
dot-config = 1

2. 确定执行规则

根据前面得到的几个变量,那么就可以确定执行Makefile line487~505的代码了。

include $(srctree)/arch/$(SRCARCH)/Makefile
export KBUILD_DEFCONFIG KBUILD_KCONFIG

config: scripts_basic outputmakefile FORCE
    $(Q)mkdir -p include/linux include/config
    $(Q)$(MAKE) $(build)=scripts/kconfig $@

%config: scripts_basic outputmakefile FORCE
    $(Q)mkdir -p include/linux include/config
    $(Q)$(MAKE) $(build)=scripts/kconfig $@

我们要先执行依赖规则 scripts_basic 和 outputmakefile,而后执行target。查找代码可以确认依赖规则如下:

# Makefile line 418
scripts_basic:
    $(Q)$(MAKE) $(build)=scripts/basic
    $(Q)rm -f .tmp_quiet_recordmcount

# Makefile line 429
outputmakefile:
ifneq ($(KBUILD_SRC),) # 不执行
    $(Q)ln -fsn $(srctree) source
    $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \
        $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
endif

3. 执行依赖规则

  • scripts_basic 
    $(Q)$(MAKE) $(build)=scripts/basic 
    build定义在scripts/Kbuild.include中,含义如下build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj 
    那么这行代码展开即是make -f scripts/Makefile.build obj=scripts/basic,跳到scripts/Makefile.build中执行,条件是obj=scripts/basic

    那我们把目光转向scripts/Makefile.build

    src := $(obj) 
    
    kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
    kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
    include $(kbuild-file)

    查找scripts/basic目录下所有的Kbuild或者Makefile,include 它们,然后编译其中的小模块,在这里编译出可执行程序fixdep.

  • outputmakefile 
    无执行代码。

4. 执行目标规则

  • $(Q)mkdir -p include/linux include/config # 创建目录 
    $(Q)$(MAKE) $(build)=scripts/kconfig $@ 
    命令展开为 
    make -f scripts/Makefile.build obj=scripts/kconfig menuconfig

  • 跳到scripts/Makefile.build中执行,条件是obj=scripts/kconfig,目标是menuconfig。 
    继续解析,执行执行scripts/kconfig中的Makefile,目标规则menuconfig。 
    menuconfig: $(obj)/mconf 
    $< $(Kconfig) 

  • 其中$(obj)/mconf的创建是Kernel Makefile中最基础也是非常精彩的部分,linux中大部分子模块均是按照这样的方式组织的。 
    在scripts/kconfig/Makefile中有如下定义: 

    mconf-objs := mconf.o zconf.tab.o $(lxdialog) 
    lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o 
    lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o 
    hostprogs-y += mconf 


    注意这里的mconf-objs和hostprogs-y 
    进入scripts/Makefile.host 

    __hostprogs := $(sort $(hostprogs-y) $(hostprogs-m)) 
    host-cmulti := $(foreach m,$(__hostprogs),\ 
    $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m)))) 
    host-cobjs := $(sort $(foreach m,$(__hostprogs),$($(m)-objs))) 
    __hostprogs := $(addprefix $(obj)/,$(__hostprogs)) 
    host-cmulti := $(addprefix $(obj)/,$(host-cmulti)) 
    host-cobjs := $(addprefix $(obj)/,$(host-cobjs)) 


    这里 
    __hostprogs := scripts/kconfig/mconf 
    host-cmulti := scripts/kconfig/mconf 
    host-cobjs := mconf.o zconf.tab.o lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o(不用关心这些.o文件是什么,我们只关心makefile的执行流程,这里在每个前面要加上前缀$(obj),即”scripts/kconfig/”)

  • 通过如下代码编译成可执行文件 

    cmd_host-cmulti = $(HOSTCC) $(HOSTLDFLAGS) -o $@ \ 
    $(addprefix $(obj)/,$($(@F)-objs)) \ 
    $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) 
    $(host-cmulti): $(obj)/%: $(host-cobjs) $(host-cshlib) FORCE 
    $(call if_changed,host-cmulti) 


    上面第二个规则匹配目标mconf,而$(host-cobjs)的匹配规则如下 

    cmd_host-cobjs = $(HOSTCC) $(hostc_flags) -c -o $@ $< 
    $(host-cobjs): $(obj)/%.o: $(src)/%.c FORCE 
    $(call if_changed_dep,host-cobjs) 


    实质上是将.c 文件编译成 .o文件,而后调用cmd_host-cobjs生成$(host-cobjs)各个目标文件。返回$(host-cmulti)规则,调用cmd_host-cmulti生成最终的可执行文件mconf,叹为观止啊。

  • 最后返回最初的menuconfig规则,现在只剩下最后一条命令:$< $(Kconfig),展开为scripts/Kconfig/mconf Kconfig,这是一条shell命令,使用刚编出来的可执行文件mconf来完成make menuconfig的最后步骤,即我们看到的图形化内核配置菜单,至此全部完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值