3 Kbuild文件

大部分内核中的Makefile都是使用Kbuild组织结构的Kbuild Makefile。这章将介绍Kbuild Makefile的语法。

对于Kbuild文件名来讲,Kbuild编译系统更倾向于使用"Makefile"这个名字,当然"Kbuild"也是可以用的。但如果"Makefile"和"Kbuild"同时存在的话,Kbuild编译系统使用的将会是"Kbuild"文件。

3.1节将是对目标定义的一个快速介绍,以后的几章会提供更详细的内容以及实例。

3.1 目标定义

目标定义是Kbuild Makefile的主要部分,也是核心部分。主要是定义了要编译的文件,所有的选项,以及到哪些子目录去执行递归操作。

最简单的Kbuild makefile 只包含一行:

例子:

obj-y += foo.o

该例子告诉Kbuild:在这目录里,有一个名为foo.o的目标文件。foo.o将从foo.c或foo.S文件编译得到。

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

例子:

obj-$(CONFIG_FOO) += foo.o

$(CONFIG_FOO)可以为y(编译进内核) 或m(编译成模块)。如果CONFIG_FOO既不是y又不是m,那么该文件就不会被编译链接了。

3.2 编译进内核 -- obj-y

Kbuild Makefile 规定所有编译进内核的目标文件都在$(obj-y)列表中。而这些列表依赖内核的配置(.config)。

Kbuild编译所有的$(obj-y)文件。然后,调用"$(LD) -r"将它们合并到一个build-in.o文件中。稍后,该build-in.o会被其父Makefile链接进vmlinux中。

$(obj-y)列表中的文件是有顺序讲究的。而且$(obj-y)列表中可以有重复项:但是当第一个文件被链接到built-in.o中后,其余重复的文件就被忽略了。

链接目标这个动作也是有顺序的,因为有些函数,例如module_init()/__initcall,将会在启动时按照他们出现的顺序被调用。所以,记住改变链接的顺序可能改变你SCSI控制器的检测顺序,从而导致你的硬盘数据损害。

例子:

# 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

3.3 编译可装载模块 -- obj-m

$(obj-m) 列举出了哪些文件要编译成可装载模块。

一个模块可以由一个文件或多个文件编译而成。如果是一个源文件,Kbuild Makefile只需简单的将其加到$(obj-m)中去就可以了。

例子:

# drivers/isdn/i4l/Makefile

obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o

注意:此例中 $(CONFIG_ISDN_PPP_BSDCOMP) 的值为'm'

如果内核模块是由多个源文件编译而成,那你就要采用上面那个例子一样的方法去声明你所要编译的模块。

Kbuild系统需要知道你所编译的模块是基于哪些文件,所以你需要通过变量:

$(<module_name>-objs)

来告诉它。

例子:

#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)中列出的所有文件进行编译,然后使用"$(LD) -r"生成isdn.o。

Kbuild recognises objects used for composite objects by the suffix -objs, and the suffix -y。

This allows the Makefiles to use the value of a CONFIG_ symbol to determine if an object is part

of a composite object.

例子:

# 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将是复合对象 ext2.o的一部分。

注意:其实,将对象编译进内核时,上面的语法同样适用。所以,如果你的 CONFIG_EXT2_FS=y,那Kbuild会按你所期望的那样,生成一个独立ext2.o文件,然后将其链接到 built-in.o中。

3.4 输出的符号

Makefile对模块输出的符号没有特殊要求。

3.5 目标库文件 -- lib-y

obj-* 中所列出的目标文件是用来编译成模块或者是链接到特定目录中的built-in.o的。同样,你也可以列出一些目标文件,它们将被包含在lib.a库中。

lib-y 所列出的目标文件将会被用来组成该目录下的一个单独的库文件。

obj-y 与 lib-y 同时列出的目标文件,因为都是可以访问的,所以该文件是不会被包含在库文件中的。

同样,lib-m 中所列出的目标文件就要包含在 lib.a 库文件中。

注意:一个Kbuild makefile可以同时列出要编译进内核的文件和要编译成库的文件。所以,在一个目录里可以同时存在 built-in.o 与 lib.a 两种文件。

例子:

# arch/i386/lib/Makefile

lib-y    := chechsum.o delay.o

这将由 checksum.o 和delay.o 两个文件创建一个库文件lib.a。为了让Kbuild 系统真正认识到这里要有一个库文件 lib.a 要创建,库文件lib.a所在的目录需要加到 libs-y 列表中。

还可参考"6.3 递归向下时要访问的目录列表"。

lib-y 的使用一般限制在 lib/ 和 arch/*/lib 中。

3.6 递归向下访问目录

其实,一个Makefile只负责编译其所在目录下的对象文件。在子目录中的文件的编译要由其所在的子目录的Makefile来管理。只要你让Kbuild系统知道它应该递归操作,那么Kbuild系统就会在其子目录中自动调用 make 从而进行递归操作。

obj-y 和 obj-m 就有这样的作用。

ext2 被放在一个单独的目录下,在fs目录下的Makefile会告诉Kbuild系统使用下面的赋值进行向下递归操作。

例子:

# fs/Makefile

obj-$(CONFIG_EXT2_FS) += ext2/

如果 CONFIG_EXT2_FS 被设置为 'y'(编译进内核)或是'm'(编译成模块),相应的 obj- 变量就会被设置,并且Kbuild就会递归向下访问 ext2 目录。

Kbuild系统只是用这些信息来决定它是否需要访问该目录,而具体怎么编译由该子目录中的Makefile来决定。

It is good practice to use a CONFIG_ variable when assigning directory    names. This allows kbuild to totally skip the directory if the corresponding CONFIG_ option is neither 'y' nor 'm'.

3.7 编辑标志

EXTRA_CFLAGS, EXTRA_AFLAGS, EXTRA_LDFLAGS, EXTRA_ARFLAGS

所有的EXTRA_ 变量只在其被定义的Kbuild Makefile文件中起作用。而且,EXTRA_ 变量可以在Kbuild Makefile中的所有命令中使用。

l          $(EXTRA_CFLAGS) 是用 $(CC) 编译C源文件时要用到的选项。

例子:

# drivers/sound/emu10kl/Makefile

EXTRA_CFLAGS += -I$(obj)

ifdef DEBUG

EXTRA_CFLAGS += -DEMU10KL_DEBUG

endif

EXTRA_CFLAGS变量是必须的,因为顶层Makefile使用 $(EXTRA_CFLAGS)作为整个源代码树的编译选项。

l          $(EXTRA_AFLAGS) 也是一个针对每个目录的选项,只不过它是用来编译汇编源代码的。

例子:

# arch/x86_64/kernel/Makefile

EXTRA_AFLAGS := -traditional

l          $(EXTRA_LDFLAGS) 和 $(EXTRA_ARFLAGS)分别与 $(LD)和 $(AR)类似,只不过,他们是针对内核的每个目录的编辑标志。

例子:

# arch/m68k/fpsp040/Makefile

EXTRA_LDFLAGS := -x

l          CFLAGS_$@, AFLSGA_$@

CFLAGS_$@ 和 AFLAGS_$@ 只能在当前Kbuild Makefile中的命令中使用。

$(CFLAGS_$@) 是 $(CC) 针对每个文件的选项。$@ 表明了具体操作的目标文件。

例子:

# 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

以上三行分别设置了aha152x.o,gdth.o 和 seagate.o的编译选项。

l          $(AFLAGS_$@)也类似,只是针对汇编语言的。

例子:

# arch/arm/kernel/Makefile

AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional

AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) –traditional

3.9 跟踪依赖

Kbuild 跟踪以下情况的依赖:

1)   所有要参与编译的文件(所有的.c 和.h文件)

2)   在参与编译文件中所要使用的 CONFIG_ 选项

3)   用于编译目标的命令行

因此,如果你改变了 $(CC) 的选项,所有受影响的文件都要重新编译。

3.10 特殊规则

特殊规则就是Kbuild编译系统不能提供所要求的支持时,所使用的规则。一个典型的例子就是在构建过程中生成的头文件。Another example are the architecture-specific Makefiles which need special rules to prepare boot images etc.

Special rules are written as normal Make rules.

Kbuild is not executing in the directory where the Makefile is located, so all special rules shall provide a relative     path to prerequisite files and target files.

Two variables are used when defining special rules:

l          $(src)

$(src) 表明Makefile所在目录的相对路径。需要定位源代码树中的文件时经常使用该变量。

l          $(obj)

$(obj) 表明目标文件所要存储目录的相对路径。经常在定位所生成的目标文件时使用该变量。

例子:

# drivers/scsi/Makefile

$(obj)/53c8xx_d.h: $(src)/53c7,8xx.scr $(src)/script_asm.pl

$(CPP) -DCHIP=810 - < $< | ... $(src)/script_asm.pl

这就是一个特殊规则,遵守着make所要求的普通语法。

目标文件依赖于两个源文件。用$(obj)来定位目标文件,用$(src)来定位源文件。

3.11 $(CC) 支持的函数

内核可能由多个不同版本的$(CC)编译,而每个版本都支持不同的功能集与选项集。Kbuild系统提供了检查 $(CC) 可用选项的基本功能。$(CC)一般情况下是gcc编译器,但也可以使用其它编译器来代替gcc。

l          as-option

as-option,当编译汇编文件(*.S)时,用来检查 $(CC) 是否支持特定选项。如果第一个选项不支持的话,可选的第二个选项就派上用场了。

例子:

# arch/sh/Makefile

cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),)

在上面的例子里,如果 $(CC) 支持选项 -Wa$(comma)-isa=$(isa-y),cflags-y就会被赋予该值。    第二个参数是可选的,当第一个参数不支持时,就会使用该值。

l          ld-option

ld-option,当链接目标文件时,用来检查 $(CC) 是否支持特定选项。如果第一个选项不支持的话,可选的第二个选项可以用来指定。

例子:

#arch/i386/kernel/Makefile

vsyscall-flags += $(call ld-option, -Wl$(comma)--hash-style=sysv)

在上面的例子中,如果 $(CC)支持选项 -Wl$(comma)--hash-style=sysv,ld-option就会被赋予该值。

第二个参数是可选的,当第一个参数不支持时,就会使用该值。

l          cc-option

cc-option,用来检查 $(CC) 是否支持特定选项,并且不支持使用可选的第二项。

例子:

# arch/i386/Makefile

cflags-y += $(call cc-option,-march=pentium-mmx,-march=i586)

在上面的例子中,如果 $(CC)支持选项 -march=pentium-mmx,cc-option就会被赋予该值,否则就赋 -march-i586。

cc-option的第二个参数是可选的。如果忽略的话,当第一个选项不支持时,cflags-y 不会被赋值。

l          cc-option-yn

cc-option-yn,用来检查 gcc 是否支持特定选项,返回'y'支持,否则为'n'。

例子:

# arch/ppc/Makefile

biarch  := $(call cc-option-yn, -m32)

aflags-$(biarch) += -a32

cflags-$(biarch) += -m32

在上面的例子里,当 $(CC) 支持 -m32选项时,$(biarch)设置为y。当$(biarch) 为y时,扩展的 $(aflags-y) 和 $(cflags-y)变量就会被赋值为:-a32 和 -m32。

l          cc-option-align

gcc版本大于3.0时,改变了函数,循环等用来声明内存对齐的选项。当用到对齐选项时,$(cc-option-align) 用来选择正确的前缀:

gcc < 3.00

cc-option-align = -malign

gcc >= 3.00

cc-option-align = -falign

例子:

CFLAGS += $(cc-option-align)-functions=4

在上面的例子中,选项 -falign-funcions=4 被用在gcc >= 3.00的时候。对于小于3.00时, 使用 -malign-funcions=4 。

l          cc-version

cc-version以数学形式返回 $(CC) 编译器的版本号。

其格式是:<major><minor>,二者都是数学。比如,gcc 3.41 会返回 0341。 当某版本的 $(CC) 在某方面有缺陷时,cc-version就会很有用。比如,选项-mregparm=3 虽然会被gcc接受,但其实现是有问题的。

例子:

# arch/i386/Makefile

cflags-y += $(shell \

if [ $(call cc-version) -ge 0300 ] ; then \

echo "-meregparm=3"; fi ;)

在上面的例子中,-mregparm=3只会在gcc的版本号大于等于3.0的时候使用。

l          cc-ifversion

cc-ifversion测试 $(CC) 的版本号,如果版本表达式为真,就赋值为最后的参数。

例子:

#fs/reiserfs/Makefile

EXTRA_CFLAGS := $(call cc-ifversion, -lt, 0402, -O1)

在这个例子中,如果 $(CC) 的版本小于4.2,EXTRA_CFLAGS就被赋值 -O1。

cc-ifversion 可使用所有的shell 操作符:-eq,-ne,-lt,-le,-gt,和-ge。

第三个参数可以像上面例子一样是个文本,但也可以是个扩展的变量或宏。

Kbuild文件的更多相关文章

  1. Linux内核Makefile文件(翻译自内核手册)

    --译自Linux3.9.5 Kernel Makefiles(内核目录documention/kbuild/makefiles.txt) kbuild(kernel build) 内核编译器 Thi ...

  2. Linux Kbuild工作原理分析(以DVSDK生成PowerVR显卡内核模块为例)

    一.引文 前篇博文<Makefile之Linux内核模块的Makefile写法分析>,介绍了Linux编译生成内核驱动模块的Makefile的写法,但最近在DVSDK下使用Linux2.6 ...

  3. Linux Kbuild文档(转)

    转载链接:http://blog.chinaunix.net/uid-10221131-id-2943265.html Linux Kbuild文档 Linux Kbuild文档 V 0.1 tang ...

  4. Linux 2.6内核Makefile浅析

    1 概述 Makefile由五个部分组成: Makefile:根目录Makefile,它读取.config文件,并负责创建vmlinux(内核镜像)和modules(模块文件). .config:内核 ...

  5. armv7a-mediatek451_001_vfp-linux-gnueabi-gcc: directory: No such file or directory 编译error

    release/vm_linux/output/hisense_android/mt5399_cn_android_JB/rel/obj/oss/source/arm_mali_ko/mali400- ...

  6. 编译android的linux kernel goldfish

    https://source.android.com/source/building-kernels.html $ export PATH=/home/hzh/oldhome/learn/androi ...

  7. 编译kernel:配置

    韦东山Linux视频第1期_裸板_UBoot_文件系统_驱动初步\第10课第2节 内核启动流程分析之配置.WMV 下面以DM9000的配置为例: 在一个编译好的内核代码里,寻找CONFIG_DM900 ...

  8. Linux源文件夹结构呈现

    1.arch文件夹: - 相关的存储在不同平台上的代码,每个平台都采用了不同的文件夹来区分. ******Alpha平台 ******Arm平台 ******Arv32平台 ******X86平台 2 ...

  9. LINUX设备驱动程序的注意事项(两)建设和执行模块

             <一>:设置測试系统 首先准备好一个内核源代码树,构造一个新内核,然后安装到自己的系统中.           <二>:HelloWorld模块 #inclu ...

随机推荐

  1. cp 命令参数

    cp命令         该命令的功能是将给出的文件或目录拷贝到另一文件或目录中,同MSDOS下的copy命令一样,功能十分强大.         语法: cp [选项] 源文件或目录 目标文件或目录 ...

  2. Java Servlet 接收上传文件

    在Java中使用 Servlet 来接收用户上传的文件,需要用到两个apache包,分别是 commons-fileupload 和 commons-io 包: 如果直接在doPost中,使用requ ...

  3. 一个关于hightcharts的x轴刻度问题

    最近做公司的一个报表系统,需要折线图,圆柱图形等来进行统计,经过最后考察,决定用当下较为流行的Highchart插件来进行实现,highchart用起来非常方便,只用对后台传过来的数据进行简单的处理后 ...

  4. Gitlab服务器搭建(For fedora23)

    1. Install and configure the necessary dependencies sudo yum install curl policycoreutils openssh-se ...

  5. 定时工作方式2实现1s定时

    定时器的几种工作方式中,除0和前面的1类似都需要初始化计数值,然后开始计数,计数溢出后,需要再次控制计数的初值,但工作模式2不同于此,工作方式2将THx和TLx分开处理,将初值存放在THx中,计数时只 ...

  6. 代码块(block)简介

    代码块是对C语言中函数的扩展,由C语言实现,所以在以C为基础的语言内都是有效的,包括Objective_C,C++和Objective-C++,在Xcode的GCG与Clang工具中是有效的,但这不属 ...

  7. ARM中的PC和AXD的PC

    R15 (PC)总是指向“正在取指”的指令,而不是指向“正在执行”的指令或正在“译码”的指令.一般来说,人们习惯性约定将“正在执行的指令作为参考点”,称之为当前第一条指令,因此PC 总是指向第三条指令 ...

  8. C# RichTextBox 获取当前显示部分的文字

    int start = richTextBox1.GetCharIndexFromPosition(new Point(0, 0)); int end = richTextBox1.GetCharIn ...

  9. activemq启动不起来,报错Address already in use: JVM_Bind

    之前莫名其妙的activemq怎么都启动不起来后来多方查询是因为widows 的ICS服务. 解决方案是,我的电脑上邮件,选择服务,然后在服务中找到Internet Connection Sharin ...

  10. 【JavaScript】JavaScript函数的参数

    要访问js函数中传入的所有参数,可以使用特殊的arguments变量.但是虽然可以像访问数组一样从arguments变量中读取参数,但arguments并非真正的数组.例如,arguments没有pu ...