KBuild MakeFile介绍

来源:互联网 发布:迦太基 汉尼拔 知乎 编辑:程序博客网 时间:2024/04/30 08:15
Linux内核Makefile分类
  • Kernel Makefile

Kernel Makefile位于Linux内核源代码的顶层目录,也叫 Top Makefile。它主要用于指定编译Linux Kernel目标文件(vmlinux)和模块(module)。这编译内核或模块是,这个文件会被首先读取,并根据读到的内容配置编译环境变量。对于内核或驱动开发人员来说,这个文件几乎不用任何修改。

  • Kbuild Makefile

Kbuild系统使用Kbuild Makefile来编译内核或模块。当Kernel Makefile被解析完成后,Kbuild会读取相关的Kbuild Makefile进行内核或模块的编译。Kbuild Makefile有特定的语法指定哪些编译进内核中、哪些编译为模块、及对应的源文件是什么等。内核及驱动开发人员需要编写这个Kbuild Makefile文件。

  • ARCH Makefile

ARCH Makefile位于ARCH/$(ARCH)/Makefile,是系统对应平台的Makefile。Kernel Top Makefile会包含这个文件来指定平台相关信息。只有平台开发人员会关心这个文件。


Kbuild Makefile
    Kbuild Makefile的文件名不一定是Makefile,尽管推荐使用Makefile这个名字。大多的Kbuild文件的名字都是Makefile。为了与其他Makefile文件相区别,你也可以指定Kbuild Makefile的名字为Kbuild。而且如果“Makefile”和“Kbuild”文件同时存在,则Kbuild系统会使用“Kbuild”文件。

  • 目标定义

Kbuild Makefile的一个最主要功能就是指定编译什么,这个功能是通过下面两个对象指定的obj-?和xxx-objs:

  • obj-?

obj-?指定编译什么,怎么编译?其中的“?”可能是“y”或“m”,“y”指定把对象编译进内核中,“m”指定把对象编译为模块。语法如下;
    obj-? = $(target).o
target为编译对象的名字。如果没有指定xxx-objs,这编译这个对象需要的源文件就是$(target).c或$(target).s。如果指定了$(target)-objs,则编译这个对象需要的源文件由$(target)-objs指定,并且不能有$(target).c或$(target).s文件。

  • xxx-objs

xxx-objs指定了编译对象需要的文件,一般只有在源文件是多个时才需要它。

只要包含了这两行,Kbuild Makefile就应该可以工作了。

  • 嵌套编译

有时一个对象可能嵌入到另一个对象的目录下,那个如何编译子目录下的对象呢?其实很简单,只要指定obj_?的对象为子目录的名字就可以了:

obj-? = $(sub_target)/

其中“?”可以是“y”或“m”,$(sub_target)是子目录名字。

  • 编译器选项

尽管在大多数情况下不需要指定编译器选项,有时我们还是需要指定一些编译选项的。

  • ccflags-y, asflags-y and ldflags-y

这些编译选项用于指定cc、as和ld的编译选项

编译外部模块
有时候我们需要在内核源代码数的外面编译内核模块,编译的基本命令是:

    make -C $(KERNEL_DIR) M=`pwd` modules
我们可以把这个命令集成到Makefile里,这样我们就可以只输入“make”命令就可以了。回想上一章的那个Makefile,它把Normal Makefile 和Kbuild  Makefile集成到一个文件中了。为了区别Kbuild Makefile 和Normal Makefile,这样我们改写Makefile为如下形式,并且添加Kbuild Makefile - “Kbuild”。

##Makefile
ifneq ($(KERNELRELEASE),)
include "Kbuild"
else
KERNEL_DIR = /lib/modules/`uname -r`/build
MODULEDIR := $(shell pwd)

.PHONY: modules
default: modules

modules:
        make -C $(KERNEL_DIR)  M=$(MODULEDIR) modules

clean distclean:
        rm -f *.o *.mod.c .*.*.cmd *.ko
        rm -rf .tmp_versions
endif

 

 

## Kbuild
MODULE_NAME = helloworld
$(MODULE_NAME)-objs := hello.o
obj-m   := $(MODULE_NAME).o

 


一般不需要在Makefile里包含如下代码,这样写完全是为了兼容老版本的Kbuild系统。KERNELRELEASE变量在Kernel Makefile里定义的,因此只有在第二次由Kbuild读取这个Makefile文件时才会解析到Kbuild的内容。

ifneq ($(KERNELRELEASE),)
include "Kbuild"
else
...
endif

 


外部头文件
有时需要连接内核源代码外部的系统头文件,但Kbuild系统默认的系统头文件都在内核源代码内部,如何使用外部的头文件呢?这个可以借助于Kbuild系统的特殊规则:

  • EXTRA_CFLAGS

EXTRA_CFLAGS可以给Kbuild系统添加外部系统头文件,
    EXTRA_CFLAGS += $(ext_include_path)
一般外部头文件可能位于外部模块源文件的目录内,如何指定呢?这可以借助$(src)或$(obj)

  • $(src)/$(obj)

$(src)是一个相对路径,它就是Makefile/Kbuild文件所在的路径。同样$(obj)就是编译目标保存的路径,默认就是源代码所在路径。


因此,我们修改Kbuild文件添加 EXTRA_CFLAGS 来包含外部头文件尽管在这个驱动里没有引用外部系统头文件:

## Kbuild
MODULE_NAME = helloworld
$(MODULE_NAME)-objs := hello.o
EXTRA_CFLAGS := -I$(src)/include
obj-m   := $(MODULE_NAME).o

 

 

 

 

  • Goal definitions

Example:

   obj-y += foo.o

告诉kbuild,在文件夹中又一个叫做foo.o的object。foo.o将会被从foo.c或者foo.S被构建。

 

如果foo.o被构建成一个模块,则将使用变量obj-mExample:

   obj-$(CONFIG_FOO) += foo.o

$(CONFIG_FOO)要么是y(built-in)要么是m(module)。如果CONFIG_FOO既不是y也不是m,那么文件将不会被编译也不会被连接。

  • Built-in object goals - obj-y

kbuild Makefiles在$(obj-y)列表中为vmlinux指明object文件。这个列表依靠内核的配置。

$(obj-y)中的文件的顺序是非常重要的。列表中允许两个相同的文件:第一个实体将被连接到built-in.o,后面的实体将会被忽略。

连接的顺序也很重要,因为在boot过程中某些函数(module_init()/_initcall)将会按顺序出现。因此,如果改变了连接顺序,将会改变你的SCSI控制器的检测顺序,你的磁盘也同时被重新编号了。

 Example:
  #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

  • Loadable module goals - obj-m

$(obj-m)指明object文件作为可装载的内核模块被构建。一个模块可能从一个或者多个源文件被构建。kbuild maefile只是简单的将源文件加到%(obj-m)

 Example:
  #drivers/isdn/i4l/Makefile
  obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o

 注意这里$(CONFIG_ISDN_PPP_BSDCOMP)是m.

Note: In this example $(CONFIG_ISDN_PPP_BSDCOMP) evaluates to 'm'。

如果一个内核模块从多个源文件构建,KBuild就必须要知道你想从哪些部分构建模块。因此,你不得不设置$(<module_name>-objs)变量来告诉KBuild。

 Example:
  #drivers/isdn/i4l/Makefile
  obj-$(CONFIG_ISDN) += isdn.o
  isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o

在这个例子中,模块名是isdn.o,Kbuild将会编译列在$(isdn-objs)的object文件,然后在这些文件的列表中调用"$(LD) -r"来产生isdn.o。

Kbuild使用后缀-objs,-y来识别混合的object文件。这允许Makefiles使用变量CONFIG_sambol来决定一个object是否是混合object的的一部分。

 Example:
  #fs/ext2/Makefile
         obj-$(CONFIG_EXT2_FS)        += ext2.o
   ext2-y                       := balloc.o bitmap.o
         ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o
 
在这个例子中,如果$(CONFIG_EXT2_FS_XATTR)是y,则xattr.o只是混合object文件ext2.o的一部分。

 注意,当你构造一个objects到内核中时,上面的语法当然也能够工作。因此,如果你让CONFIG_EXT2=Y,KBuild将会为你构建一个独立的ext2.o文件,并且连接到built-in.o。

  • Library file goals - lib-y

obj-*连接的Objects在指明的文件夹中被用作模块或者综合进built-in.o。也又可能被列出的objects将会被包含进一个库,lib.a。所有用lib-y列出的objects在那个文件夹中被综合进单独的一个库。列在obj-y和附加列在lib-y中的Objects将不会被包含在库中,因为他们将会被任意的存取。对于被连接在lib-m中,连续的objects将会被包含在lib.a中。值得注意的是kbuild makefile可能列出文件用作built-in,并且作为库的一部分。因此,同一个文件夹可能包含一个built-in.o和lib.a文件。

Example:
  #arch/i386/lib/Makefile
  lib-y    := checksum.o delay.o

这里讲会创建一个基于checksum.o和delay.o的库文件。对于kbuild,识别一个lib.a正在被构建,这个文件夹应该被列在libs-y中。lib-y的使用方法通常被限制在lib/和arc/*/lib中。

  • Descending down in directories

一个Makefile只负责在他自己的文件夹中构建objects。 在子文件夹中的文件应该由子文件夹中的Makefiles来照顾。如果你知道他们,build系统将会自动递归地用在子文件夹中的make。

在这种情况下obj-yobj-m就被使用了。ext2存在于不同的文件夹中,Makefile出现在fs/,则告诉kbuild从后面的参数下来。

Example:
  #fs/Makefile
  obj-$(CONFIG_EXT2_FS) += ext2/

 如果CONFIG_EXT2_FS被设置成y(built-in)或者m(modular),相应的obj-变量将会被设置,并且kbuild将会从ext2文件夹继承下来。Kbuild只会使用这些信息来决定它需要访问这些文件夹,而在子文件夹中的Makefile来指明哪些是modules哪些是built-in。

当赋值文件夹名字的时候,使用CONFIG_variable是很好的选择。这允许kbuild完全的跳过文件夹,而不管CONFIG_option是否是y或者m。

  • Compilation flags

    EXTRA_CFLAGS, EXTRA_AFLAGS, EXTRA_LDFLAGS, EXTRA_ARFLAGS。

所有的EXTRA_ variables只应用在kbuild中,他们被赋值的地方。EXTRA_variables应用在kbuild makefile中所有的可执行的命令。$(EXTRA_CFLAGS) 指明用$(CC)编译C文件的时候的选项。

 Example:
  # drivers/sound/emu10k1/Makefile
  EXTRA_CFLAGS += -I$(obj)
  ifdef DEBUG
      EXTRA_CFLAGS += -DEMU10K1_DEBUG
  endif

这里的变量是必须的,因为顶层的Makefile拥有变量$(CFLAGS)并且用它来作为整个树的编译标志当编译汇编源文件的时候$(EXTRA_AFLAGS),和每个文件夹的选项是相似的。

 Example:
  #arch/x86_64/kernel/Makefile
  EXTRA_AFLAGS := -traditional

$(EXTRA_LDFLAGS)$(EXTRA_ARFLAGS) 对于每个文件夹的$(LD)和$(AR)选项是类似的。

 Example:
  #arch/m68k/fpsp040/Makefile
  EXTRA_LDFLAGS := -x

 CFLAGS_$@, AFLAGS_$@

 CFLAGS_$@AFLAGS_$@只应用到当前kbuild makefile的命令。

 $(CFLAGS_$@) 为每个文件的$(CC)指明选项。$@
 部分有一个字面上的值,指明它是为那个文件。

 Example:
  # drivers/scsi/Makefile
  CFLAGS_aha152x.o =   -DAHA152X_STAT -DAUTOCONF
  CFLAGS_gdth.o    = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ \
         -DGDTH_STATISTICS
  CFLAGS_seagate.o =   -DARBITRATE -DPARITY -DSEAGATE_USE_ASM

 These three lines specify compilation flags for aha152x.o,
 gdth.o, and seagate.o

 $(AFLAGS_$@) is a similar feature for source files in assembly
 languages.

 Example:
  # arch/arm/kernel/Makefile
  AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional
  AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) -traditional

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 洛克王国得到了魔攻巨蟹座怎么办 在育碧下载游戏下一半不下了怎么办 轩辕传奇单机版忘记哪个区了怎么办 登腾讯游戏动态密码啥意思怎么办 说了不该说的话别人不原谅怎么办 轩辕传奇手游金币用错了怎么办 神秘时代4法杖按键冲突怎么办 孕2个月发烧38度怎么办 不知道怀孕喝了止咳糖浆怎么办? 小孩刮头发的备皮刀割住手怎么办? 天梭手表里面的刻度掉了怎么办 国战天下手游帐号丢失怎么办 肺力咳合剂一次喝了50多了怎么办 头孢和藿香正气水一起吃了怎么办 小儿胃蛋自酶合剂吃多了怎么办 刚出生的婴儿很容易被惊醒怎么办 1个多月的宝宝小腿不直怎么办 20个月宝宝腿不直小腿外八怎么办 小孩手青枝骨骨折拆石膏还弯怎么办 宝宝喝柴胡注射剂有不良反应怎么办 九个月宝宝便秘拉不出来怎么办 一岁四个月的宝宝便秘怎么办 热血三国3要塞打不过去怎么办 清香木夏天有黄叶和掉叶怎么办 生完宝宝妊娠纹还在继续疯长怎么办 陌陌不能最小化观看直播视频怎么办 苏州园区公积金密码忘记了怎么办 房产企业申请破产买的房子怎么办 被业务员骗了买了保险怎么办 孩子特别害怕老师严厉的批评怎么办 4k电视看有线电视不清晰怎么办 移动9.9流量4g网用完了怎么办 东方头条验证码已经被注册了怎么办 打王者两个人吵架被夹在中间怎么办 顾客拿过期的食品过来投诉怎么办 老婆总是埋怨我父母我该怎么办? 代款公司如果使用暴力追债怎么办 法院拍卖款分配有疑意怎么办 法院拍卖买到的房子里有户口怎么办 新注册手机邮箱不和电脑同步怎么办 移动4g盒当月流量封顶怎么办