转自:http://blog.csdn.net/tommy_wxie/article/details/7280463

版权声明:本文为博主原创文章,未经博主允许不得转载。

 
 

1 概述

Makefile由五个部分组成:

  • Makefile:根目录Makefile,它读取.config文件,并负责创建vmlinux(内核镜像)和modules(模块文件)。
  • .config:内核配置文件(一般由make menuconfig生成)。
  • arch/$(ARCH)/Makefile:目标处理器的Makefile。
  • scripts/Makefile.*:所有kbuild Makefile的规则,它们包含了定义/规则等。
  • kbuild Makefiles:每个子目录都有kbuild Makefile,它们负责生成built-in或模块化目标。(注意:kbuild Makefile是指使用kbuild结构的Makefile,内核中的大多数Makefile都是kbuild Makefile。)

2 kbuild文件

2.1 obj-y和obj-m

最简单的kbuild Makefile可以仅包含:

obj-$(CONFIG_FOO) += foo.o

其中$(CONFIG_FOO)可以等于y或m,它的值由.config文件给出。如果$(CONFIG_FOO)既不是y也不是m,那么该文件不会被编译和链接

当$(CONFIG_FOO)等于y时,上面语句等价于obj-y += foo.o,它告诉kbuild在当前目录下,有一个叫做foo.o的目标文件,它将从foo.c或则foo.S编译得到。

当$(CONFIG_FOO)等于m时,表示foo.o需要被编译成模块。

2.1.1 obj-y生成built-in.o

Kbuild编译所有的$(obj-y)文件,并调用”$(LD) -r”把所有这些文件合并到built-in.o文件。这个built-in.o会被上一级目录的Makefile使用,最终链接到vmlinux中。

2.1.2 目标由多个源文件编译得到

如果某个目标由多个源文件编译得到,那么可以通过$(<module_name>-objs)或$(<module_name>-y)把这些源文件告诉kbuild。Kbuild能够识别后缀-objs和-y,例如:

#drivers/isdn/i4l/Makefile

obj-$(CONFIG_ISDN) += isdn.o

isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o

Kbuild会编译所有$(isdn-objs)中的对象,并调用"$(LD) -r"把它们链接成isdn.o文件。

下面是一个使用后缀-y的例子。后缀-y的好处是,可以使用CONFIG_XXX符号来决定是否加入某些源文件(.o从对应的.c或.S编译得到):

#fs/ext2/Makefile

obj-$(CONFIG_EXT2_FS)        += ext2.o

ext2-y                       := balloc.o bitmap.o

ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o

2.1.3 调用子目录Makefile

Makefile只负责编译当前目录中的对象。子目录中的对象,由子目录中的Makefile负责。如何让make调用子目录中的Makefile?答案是把子目录包含到obj-y或obj-m中。例如:

#fs/Makefile

obj-$(CONFIG_EXT2_FS) += ext2/

当CONFIG_EXT2_FS为y或m时,kbuild系统会在ext2目录中调用make命令(也即调用ext2目录中的Makefile)

2.2 lib-y和lib-m

在一个目录下,obj-y所列出的文件,将被编译成built-in.o文件,而lib-y或lib-m所列出的文件,将在当前目录下生成lib.a文件。

注意:一般lib-y或lib-m只用在lib/和arch/*/lib这两个目录中。

2.3 编译选项变量

2.3.1 ccflags-y、asflags-y、ldflags-y

这三个变量只在当前Makefile中有效。补充:$(KBUILD_CFLAGS)是定义在根目录Makefile中的变量,它适用于整个内核数。

2.3.2 subdir-ccflags-y、subdir-asflags-y

这两个变量作用于当前Makefile及其所有子目录。

2.3.2 CFLAGS_$@、AFLAGS_$@

这两个变量只在当前Makefile中有效。$@可以用来指定文件名,让不同文件可以使用不同的编译选项。例如:

# 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

2.4 $(src)、$(obj)、$(kecho)

$(src)指向当前Makefie所在目录的相对路径。$(obj)指向用来保存目标文件的相对目录。示例如下:

#drivers/scsi/Makefile

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

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

这里,$(src)等于drivers/scsi/,$(obj)同样也等于drivers/scsi/。

使用“make -s”命令时,只会输出警告和错误信息。$(kecho)能够将其后的内容输出到标准输出流(一般就是显示器),前提是没有使用“make -s”。示例如下:

#arch/blackfin/boot/Makefile

$(obj)/vmImage: $(obj)/vmlinux.gz

$(call if_changed,uimage)

@$(kecho) 'Kernel: $@ is ready'

2.5 $(CC)相关功能

2.5.1 as-option、ld-option、cc-option

当编译、链接文件时,xx-opiton可以用来检查当前使用的$(CC)是否支持给出的编译选项。如前者不支持,可使用后者。例如:

#arch/sh/Makefile

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

如果当前的$(CC)不支持-Wa$(comma)-isa=$(isa-y),那么可以使用第二个编译选项(这里为空)。

2.5.2 cc-option-yn

cc-option-yn用来检查$(CC) 是否支持给出的编译选项。如支持,返回y,否则返回n。例如:

#arch/ppc/Makefile

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

aflags-$(biarch) += -a32

cflags-$(biarch) += -m32

2.5.3 cc-option-align

gcc在3.0之后改变了指定函数、循环等对齐选项的类型。gcc < 3.00时,cc-option-align = -malign;gcc >= 3.00时,cc-option-align = -falign。使用$(cc-option-align)来选择正确的前缀。例如:

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

2.5.4 cc-version、cc-ifversion 、cc-fullversion

cc-version返回$(CC)版本。如$(CC)为gcc 3.41,那么cc-version返回0341。例如:

#arch/i386/Makefile

cflags-y += $(shell /

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

echo "-mregparm=3"; fi ;)

cc-ifversion在版本符合条件的前提下返回最后一个参数。示例如下:

#fs/reiserfs/Makefile

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

如果$(CC)版本低于4.2,那么ccflags-y将等于-O1。

cc-fullversion给出更详细的版本信息,例如:

#arch/powerpc/Makefile

$(Q)if test "$(call cc-fullversion)" = "040200" ; then /

echo -n '*** GCC-4.2.0 cannot compile the 64-bit powerpc ' ; /

false ; /

fi

2.5.5 cc-cross-prefix

cc- cross-prefix用于检查是否存在给定前缀的$(CC),如存在,返回第一个匹配的前缀,否则返回空。如有多个前缀需要匹配,各前缀之间使用单个空格隔开。例如:

#arch/m68k/Makefile

ifneq ($(SUBARCH),$(ARCH))

ifeq ($(CROSS_COMPILE),)

CROSS_COMPILE := $(call cc-cross-prefix, m68k-linux-gnu-)

endif

endif

(注:本文所述内容来自kernel-2.6.30/Documentation/kbuild/makefiles.txt,适用于Linux 2.6内核)

从Linux内核2.6开始,Linux内核的编译采用Kbuild系统,这同过去的编译系统有很大的不同, 尤其对于Linux内核模块的编译。在新的系统下,Linux编译系统会两次扫描Linux的Makefile:首先编译系统会读取Linux内核顶层的 Makefile,然后根据读到的内容第二次读取Kbuild的Makefile来编译Linux内核。
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 Makefile

## 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)就是编译目标保存的路径,默认就是源代码所在路径。

Linux 2.6内核Makefile浅析【转】的更多相关文章

  1. Linux 2.6内核Makefile浅析

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

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

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

  3. linux内核Makefile整体分析

    转自:http://www.cnblogs.com/amanlikethis/p/3675486.html <请阅读原文> 一.概述 1.本文的意义 众多的资料(<嵌入式Linux应 ...

  4. linux内核makefile概览

    linux内核makefile概览 本博客参照内核官方英文文档 linux的内核makefile主要用于编译整个内核源码,按照用户的需求生成各种目标文件,对于用户来说,编译内核时非常简单的,只需要几个 ...

  5. [内核同步]浅析Linux内核同步机制

    转自:http://blog.csdn.net/fzubbsc/article/details/37736683?utm_source=tuicool&utm_medium=referral ...

  6. Helloworld模块之内核makefile详解

    Hello World 模块以及对应的内核makefile详解 hello.c: #include <linux/module.h> //所有模块都需要的头文件 #include < ...

  7. linux驱动系列之makefile

    在linux环境下做嵌入式无论是编写应用程序还是驱动程序等等,都需要用make来进行程序的编译,就需要学会自己编写Makefile.Makefile主要的作用有3点:1.决定编译哪些文件 2.怎样编译 ...

  8. 编译kernel:内核makefile的作用

    < 嵌入式linux应用完全开发手册 > 韦东山 内核Makefile的使命: 编译哪些内核文件? 读取各级子目录makefile, .config, auto.conf, Kbuild, ...

  9. Linux系统启动那些事—基于Linux 3.10内核【转】

    转自:https://blog.csdn.net/shichaog/article/details/40218763 Linux系统启动那些事—基于Linux 3.10内核 csdn 我的空间的下载地 ...

随机推荐

  1. Halcon环境搭建

    1.Visual Studio 2017安装教程 2.Qt5.9安装教程 3.VS2017中Qt插件安装教程

  2. Visual Studio 2017离线安装包

    点击下载

  3. Leetcode 684.冗余连接

    冗余连接 在本问题中, 树指的是一个连通且无环的无向图. 输入一个图,该图由一个有着N个节点 (节点值不重复1, 2, ..., N) 的树及一条附加的边构成.附加的边的两个顶点包含在1到N中间,这条 ...

  4. nonebot 源码阅读笔记

    前言 nonebot 是一个 QQ 消息机器人框架,它的一些实现机制,值得参考. nonebot NoneBot 初始化(配置加载) 阅读 nonebot 文档,第一个示例如下: import non ...

  5. struts2 action中获取request session application的方法

    共四种方式: 其中前两种得到的是Map<String,Object>  后两种得到的才是真正的request对象 而Map就是把request对象中的属性取出做成了键值对而已. [方法一] ...

  6. 平面最近点对(HDU 1007)

    题解:点击 #include <stdio.h> #include <string.h> #include <algorithm> #include <ios ...

  7. 201621044079WEEK06-接口、内部类

    作业06-接口.内部类 1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图或相关笔记,对面向对象思想进行一个总结. 注1:关键词与内容不求多 ...

  8. maven打包遇到的问题

    1.javax.servlet.jsp.tagext不存在 maven打包报程序包javax.servlet.jsp.tagext不存在或者maven打包报程序包javax.servlet.jsp不存 ...

  9. delphi中写SQL语句中变量的注意事项

    1.procedure TForm1.btn1Click(Sender: TObject); var   s: String; begin   S := 'select * from TMarketI ...

  10. IE6中png背景图片透明的最好处理方法

    在IE6浏览器下png(24位)的图片显示是不能透明的. 1.处理办法就是用DDPngMin.js <!--[if IE 6]> <script src="js/DDPng ...