linux kernel 的makefile的组织结构(转)

背景知识:
背景知识一:Kconfig介绍:
在#make menuconfig 时,所显示的Menu list是由各层Kconfig组成的。
最底层Kconfig存放在 ~/arch/i386/Kconfig. 以此为头,它会一层层使用source来把需要加入的各个目录中Keconfig添加近来。
例如:source "drivers/Kconfig"
则将~/drivers/Kconfig添加进Menu list中。

背景知识二:Kconfig写法语义:
config HID
tristate "Generic HID support"
depends on INPUT
default y
解释如下:
config HID :表示此条目与CONFIG-HID对应。CONFIG-HID会在Makefile中用到。

tristate "Generic HID support" 引号内的内容是会显示到Menu list中的。tristate表示这一项是三态的。

depends on INPUT:依赖于INPUT这一项。如果没有选中INPUT,则Menu list不会显示这项。

default y :缺省被选中。



背景知识三:built-in.o
vmlinux是Linux源码编译后未压缩的内核, vmlinux是由arch/i386/kernel/head.o和arch/i386/kernel/init_task.o以及各个相关子目录下的built-in.o链接而成的。


背景知识四:Kernel Makefile
Kernel中Makefile的体系以及如何编译的,其实Sam一直是一知半解的。
其中,kernel目录中的Makefile被称为底层Makefile。
当使用类似#make menuconfig配置内核成功后,会生成 .config文件。
换句话说:make menuconfig 时,Makefile会从~/arch/i386/Kconfig读取Kconfig.然后根据用户的选择。生成.config文件。
例如:在drivers/hid/Kconfig:
config HID
tristate "Generic HID support"
如果用户选中Y,则在.config中会反映出来:
CONFIG_HID=y
则在~/drivers/Makefile中可以看到:
obj-$(CONFIG_HID) += hid/
表明:如果CONFIG_HID是Y,则把hid目录添加到要编译的目录中了。
进入到/driver/hid目录,则看到:
hid-objs := hid-core.o hid-input.o
表明这两个.o文件是一定会被编译出的。
obj-$(CONFIG_HID) += hid.o
表明:如果CONFIG_HID是Y,则hid.o会被编译出来。并built-in.
如果是 =m. 则hid.o被编译出来,但最后被做成modules(ko)
背景知识五:KBuild Make:
Linux内核的Makefile与我们平时写的Makefile有所不同,它由五部分组成:
1.Makefile : 顶层Makefile。
2. .config: kernel配置文件。
3. arch/xxx/Makefile: 具体架构的Makefile。
4. scripts/Makefile.xxx : 通用规则。
5. kbuild Makefile: 整个kernel中大约有数百个这种文件。

#make menuconfig后,生成 kernel配置文件: .config。
顶层Makefile读取.config.
顶层Makefile通过解析 .config来决定递归访问哪些目录中的Kbuild Makefile .
这个过程中,Kbuild Makefile会按.config的设置,逐个添加文件列表,以供最后的编译使用。
最简单的KBuild Makefile如下:
obj-y += foo.o
表明:Kbuild在这目录里,有一个名为foo.o的目标文件。foo.o将从foo.c或foo.S文件编译得到。并且它会被包入built-in中去。
所有编译进内核的目标文件都存在$(obj-y)列表中。而这些列表依赖内核的配置。Kbuild编译所有的$(obj-y)文件。然后,调用"$(LD) -r"将它们合并到一个build-in.o文件中。稍后,该build-in.o会被其父Makefile联接进vmlinux中。

如果foo.o要编译成一模块,那就要用obj-m了。所采用的形式如下:
obj-m += foo.o



例一:
在 ~/driver/hid/hid-core.c中,有以下语句,即内核insmod接口hid_init.
module_init(hid_init);
也就是说,当此模块被buildin或者作为module insmod时,kernel会自动调用hid_init.
然后查看 ~/driver/hid/Makefile,发现
hid-objs := hid-core.o hid-input.o
表明只要hid这个目录被加入,就会生成hid-core.o.
只好去看上一层目录中怎样会进入hid目录:
obj-$(CONFIG_HID) += hid/
表明只要CONFIG_HID=Y,m. 则hid目录被加入。
但用户作了什么,hid目录被加入编译呢?则看~/drivers/hid/Kconfig
config HID
tristate "Generic HID support"
以此得之只要在make menuconfig中选中此项,则hid-core.o被编译出来。


例2:
Sam想要研究USB Keyboard & Mouse driver. 在 make menuconfig时,需要选中:
config USB_HID
tristate "USB Human Interface Device (full HID) support"
则查看Makefile。发现只要选中CONFIG_USB_HID.则会编译出usb_hid.o
但~/drivers/hid/usbhid目录中却没有usbhid.c。那usbhid.o如何生成的呢?
drivers/hid/usbhid目录中,有个.usbhid.o.cmd文件。
 
linux kernel makefile 
描述linux kernel 的makefile的组织结构,什么是linux kernel 和 makefile 不用说了。

1. 概述

kernel的makefile分为5个部分:

Makefile 最外面的Makefile 
.config kernel的配置文件 
arch/$(ARCH)/Makefile 不同架构cpu的makefile 

scripts/Makefile.* 规则文件

kbuild Makefiles 500多个makefile文件 

来看看kbuild makefile文件的构造规则定义。kbuild文件是组织kernel选项的文件。你会看到kbuild 和makefile 在一般同时存在一个目录里的。

目标定义:

一般都会用到此定义,此行的目的是要编译成foo.o 文件,而源文件是默认的foo.c或者是foo.s 。源文件在kbuild文件的同级目录里。

obj-y += foo.o

如果要将此编译成一个模块,则需要用ojb-m 。如果想通过kernel的配置传递此参数,则需要写下面的。

obj-$(CONFIG_FOO) += foo.o

(CONFIG_FOO) 就是你在kernel选项里配置的,如果你没有选中是built-in 还是 module,则此变量是y 或者 m的其他值,则不会编译此文件。


built-in 目标文件:

当你obj-y 的时候,他们将会把所有的obj-y files 都编译进去一个大的 built-in.o 目标文件。此后,会根据最上层的Makefile 链接成一个kernel image。


#drivers/isdn/i4l/Makefile # Makefile for the kernel ISDN subsystem and device drivers. # Each configuration option enables a list of files. obj-$(CONFIG_ISDN) += isdn.o obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
需要注意的是,您需要注意这些 目标文件的顺序。
因为一些函数例如(module_init() / __initcall) 是按照他们出现的顺序被调用的。

ojb-m 目标:

这个是指要编译成模块。一个模块可以由一个源文件或者多个组成。
linux/2.6.20.6/make menuconfig 


当在顶层目录执行”make menuconfig”会执行顶层Makefile 第415行的规则 

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

这里”menuconfig”与模式”%config”匹配。所以其执行的规则如下: 

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

这个规则有三个依赖:scripts_basic、outputmakefile、FORCE。下面看一下这三个依赖: 

1、 FORCE 

首先分析一下这个依赖,它的规则定式义在1485行: 

PHONY += FORCE 
FORCE: 

这个规则没有命令也没有依赖,它的目标也不是一个存在的文件名。在执行此规则时,目标FORCE总会被认为是最新的。这样当它作为其它规则的依赖时,因为依赖总被认为被更新过的,所以那个规则的中定义的命令总会被执行。 

2、 scripts_basic 

这个依赖的规则在347行定义: 

scripts_basic: 
$(Q)$(MAKE) $(build)=scripts/basic 

build这个变量定义在scripts/kbuild.include的114行: 

build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj 

所以上面的规则可写成如下形式: 

scripts_basic: 
$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj=scripts/basic 

这个规则的命令最终会进入scripts目录,执行Makefile.build文件,并传递参数obj=scripts/basic. 

在Makefile.build的第5行有: 

src := $(obj) 

这就把传递进来的值赋给了src,所以 

src := scripts/basic 

从第16行开始的两行把src (即scripts/basic)目录下的Makefile包含进来(如果有Kbuild则包含Kbuild) 

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

在第19行包含了scripts/Makefile.lib进来, 

在Makefile.build的第83行,是make在Makefile.build中遇到的第一个目标 

__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \ 
$(if $(KBUILD_MODULES),$(obj-m)) \ 
$(subdir-ym) $(always) 
@: 

KBUILD_BUILTIN在顶层Makefile的第207行定义 

KBUILD_BUILTIN := 1 

如果执行”make modules”,会在214行开始对其进行一些处理 

ifeq ($(MAKECMDGOALS),modules) 
KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1) 
endif 

所以我们这里 KBUILD_BUILTIN :=1 

KBUILD_MODULES在顶层Makefile的第206行定义, 

KBUILD_MODULES := 

如果执行”make all”、”make _all”、”make modules”、”make”中任一个命令,则在222行开始会对这个变量进行处理 

ifneq ($(filter all _all modules,$(MAKECMDGOALS)),) 
KBUILD_MODULES := 1 
endif 

ifeq ($(MAKECMDGOALS),) 
KBUILD_MODULES := 1 
endif 

因此,我们这里KBUILD_MODULES := 

分析了这两个变量后,上面的规则可重新写为 

__build: $(builtin-target) $(lib-target) $(extra-y)) $(subdir-ym) $(always) 
@: 

这就是通过规则 

scripts_basic: 
$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj=scripts/basic 

在scripts/Makefile.build文件中执行的第一个规则, 

规 则中的依赖由几个变量$(builtin-target) $(lib-target) $(extra-y)) $(subdir-ym) $(always)表示。规则的命令是一个冒号命令”:”,冒号(:)命令是bash的内建命令,通常把它看作true命令。bash的help解释 (help :)为:No effect; the command does nothing. A zero exit code is returned.(没有效果,该命令是空操作,退出状态总是0)。 
__build: $(builtin-target) $(lib-target) $(extra-y)) $(subdir-ym) $(always) 
@: 

构建一些依赖目标,这里主要是构建$(always)变量指定的目标。其他变量在scripts/basic/Makefile中并没有定义。 

3、 outputmakefile 

回到顶层Makefile中看规则 

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

中的outputmakefile参数构建规则在357行开始定义 

outputmakefile: 
ifneq ($(KBUILD_SRC),) 
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \ 
$(srctree) $(objtree) $(VERSION) $(PATCHLEVEL) 
endif 

这个规则的命令运行一个shell脚本scripts/mkmakefile,并传递四个参数。这个脚本主要是在$(objtree)参数指定的目录中生成一个Makefile文件。由于这里KBUILD_SRC为空,所以这个脚本并不会被执行

回头再看看刚才那个规则 

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

在他的依赖被处理完后,开始执行规则的命令。第一个命令创建了两个目录,第二个命令扩展后为 

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

这 个命令依然是执行scripts/Makefile.build这个makefile文件。并执行它里面menuconfig的规则。根据上面的分析,在 Makefile.build会包含scripts/kconfig/Makefile文件。然后执行以menuconfig为目标的规则,在 scripts/kconfig/Makefile的13行定义 

menuconfig: $(obj)/mconf 
$< arch/$(ARCH)/Kconfig 

从这个命令可以看出,最终会运行arch/arm/Kconfig这个脚本,出现配置界面
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页