返回首页
当前位置: 主页 > 精通Office > Ubuntu教程 >

Linux内核Makefile浅析

时间:2012-04-17 20:41来源:知行网www.zhixing123.cn 编辑:麦田守望者

1. 配置系统的基本结构
  Linux内核的配置系统由三个部分组成,分别是:

  Makefile:分布在 Linux 内核源代码中的 Makefile,定义 Linux 内核的编译规则;

  配置文件(config.in):给用户提供配置选择的功能;

  配置工具:包括配置命令解释器(对配置脚本中使用的配置命令进行解释)和配置用户界面(提供基于字符界面、基于 Ncurses 图形界面以及基于 Xwindows 图形界面的用户配置界面,各自对应于 Make config、Make menuconfig 和 make xconfig)。

  这些配置工具都是使用脚本语言,如 Tcl/TK、Perl 编写的(也包含一些用 C 编写的代码)。本文并不是对配置系统本身进行分析,而是介绍如何使用配置系统。所以,除非是配置系统的维护者,一般的内核开发者无须了解它们的原理,只需要知道如何编写 Makefile 和配置文件就可以。所以,在本文中,我们只对 Makefile 和配置文件进行讨论。另外,凡是涉及到与具体 CPU 体系结构相关的内容,我们都以 arm 为例,这样不仅可以将讨论的问题明确化,而且对内容本身不产生影响。

  2. Makefile

  2.1 Makefile 概述

  Makefile 的作用是根据配置的情况,构造出需要编译的源文件列表,然后分别编译,并把目标代码链接到一起,最终形成 Linux 内核二进制文件。

  由于 Linux 内核源代码是按照树形结构组织的,所以 Makefile 也被分布在目录树中。Linux 内核中的 Makefile 以及与 Makefile 直接相关的文件有:

  Makefile:顶层 Makefile,是整个内核配置、编译的总体控制文件。

  .config:内核配置文件,包含由用户选择的配置选项,用来存放内核配置后的结果(如 make config)。

  archMakefile 还作了扩充。

  常用的变量有以下几类:

  1) 版本信息

  版本信息有:VERSION,PATCHLEVEL, SUBLEVEL, EXTRAVERSION,KERNELRELEASE。版本信息定义了当前内核的版本,比如 VERSION=2,PATCHLEVEL=4,SUBLEVEL=18,EXATAVERSION=-rmk7,它们共同构成内核的发行版本 KERNELRELEASE:2.4.18-rmk7

  2) CPU 体系结构:ARCH

  在顶层 Makefile 的开头,用 ARCH 定义目标 CPU 的体系结构,比如 ARCH:=arm 等。许多子目录的 Makefile 中,要根据 ARCH 的定义选择编译源文件的列表。

  3) 路径信息:TOPDIR, SUBDIRS

  TOPDIR 定义了 Linux 内核源代码所在的根目录。例如,各个子目录下的 Makefile 通过 $(TOPDIR)/Rules.make 就可以找到 Rules.make 的位置。

  SUBDIRS 定义了一个目录列表,在编译内核或模块时,顶层 Makefile 就是根据 SUBDIRS 来决定进入哪些子目录。SUBDIRS 的值取决于内核的配置,在顶层 Makefile 中 SUBDIRS 赋值为 kernel drivers mm fs net ipc lib;根据内核的配置情况,在 archMakefile 中定义,用来确定被最先链接进 vmlinux 的文件列表。比如,对于 arm 系列的 CPU,HEAD 定义为:

  HEAD := arch/arm/kernel/head-$(PROCESSOR).o \

  arch/arm/kernel/init_task.o

  表明 head-$(PROCESSOR).o 和 init_task.o 需要最先被链接到 vmlinux 中。PROCESSOR 为 armv 或 armo,取决于目标 CPU。 CORE_FILES,NETWORK,DRIVERS 和 LIBS 在顶层 Makefile 中定义,并且由 archMakefile 中定义,比如:

  # arch/arm/Makefile

  LINKFLAGS :=-p -X -T arch/arm/vmlinux.lds

  6) 配置变量CONFIG_*

  .config 文件中有许多的配置变量等式,用来说明用户配置的结果。例如 CONFIG_MODULES=y 表明用户选择了 Linux 内核的模块功能。

  .config 被顶层 Makefile 包含后,就形成许多的配置变量,每个配置变量具有确定的值:y 表示本编译选项对应的内核代码被静态编译进 Linux 内核;m 表示本编译选项对应的内核代码被编译成模块;n 表示不选择此编译选项;如果根本就没有选择,那么配置变量的值为空。

  2.3 Rules.make 变量

  前面讲过,Rules.make 是编译规则文件,所有的 Makefile 中都会包括 Rules.make。Rules.make 文件定义了许多变量,最为重要是那些编译、链接列表变量。

  O_OBJS,L_OBJS,OX_OBJS,LX_OBJS:本目录下需要编译进 Linux 内核 vmlinux 的目标文件列表,其中 OX_OBJS 和 LX_OBJS 中的 "X" 表明目标文件使用了 EXPORT_SYMBOL 输出符号。

  M_OBJS,MX_OBJS:本目录下需要被编译成可装载模块的目标文件列表。同样,MX_OBJS 中的 "X" 表明目标文件使用了 EXPORT_SYMBOL 输出符号。

  O_TARGET, L_TARGET:每个子目录下都有一个 O_TARGET 或 L_TARGET,Rules.make 首先从源代码编译生成 O_OBJS 和 OX_OBJS 中所有的目标文件,然后使用 $(LD) -r 把它们链接成一个 O_TARGET 或 L_TARGET。O_TARGET 以 .o 结尾,而 L_TARGET 以 .a 结尾。

  2.4 子目录 Makefile

  子目录 Makefile 用来控制本级目录以下源代码的编译规则。我们通过一个例子来讲解子目录 Makefile 的组成:

  >

  #

  # Makefile for the linux kernel.

  #

  # All of the (potential) objects that export symbols.

  # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.

  export-objs := tc.o

  # Object file lists.

  obj-y :=

  obj-m :=

  obj-n :=

  obj- :=

  obj-$(CONFIG_TC) += tc.o

  obj-$(CONFIG_ZS) += zs.o

  obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o

  # Files that are both resident and modular: remove from modular.

  obj-m := $(filter-out $(obj-y), $(obj-m))

  # Translate to Rules.make lists.

  L_TARGET := tc.a

  L_OBJS := $(sort $(filter-out $(export-objs), $(obj-y)))

  LX_OBJS := $(sort $(filter $(export-objs), $(obj-y)))

  M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))

  MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))

  include $(TOPDIR)/Rules.make

  a) 注释

  对 Makefile 的说明和解释,由#开始。

  b) 编译目标定义

  类似于 obj-$(CONFIG_TC) += tc.o 的语句是用来定义编译的目标,是子目录 Makefile 中最重要的部分。编译目标定义那些在本子目录下,需要编译到 Linux 内核中的目标文件列表。为了只在用户选择了此功能后才编译,所有的目标定义都融合了对配置变量的判断。

  前面说过,每个配置变量取值范围是:y,n,m 和空,obj-$(CONFIG_TC) 分别对应着 obj-y,obj-n,obj-m,obj-。如果 CONFIG_TC 配置为 y,那么 tc.o 就进入了 obj-y 列表。obj-y 为包含到 Linux 内核 vmlinux 中的目标文件列表;obj-m 为编译成模块的目标文件列表;obj-n 和 obj- 中的文件列表被忽略。配置系统就根据这些列表的属性进行编译和链接。

  export-objs 中的目标文件都使用了 EXPORT_SYMBOL() 定义了公共的符号,以便可装载模块使用。在 tc.c 文件的最后部分,有 "EXPORT_SYMBOL(search_tc_card);",表明 tc.o 有符号输出。

  这里需要指出的是,对于编译目标的定义,存在着两种格式,分别是老式定义和新式定义。老式定义就是前面 Rules.make 使用的那些变量,新式定义就是 obj-y,obj-m,obj-n 和 obj-。Linux 内核推荐使用新式定义,不过由于 Rules.make 不理解新式定义,需要在 Makefile 中的适配段将其转换成老式定义。

  c) 适配段

  适配段的作用是将新式定义转换成老式定义。在上面的例子中,适配段就是将 obj-y 和 obj-m 转换成 Rules.make 能够理解的 L_TARGET,L_OBJS,LX_OBJS,M_OBJS,MX_OBJS。

  L_OBJS := $(sort $(filter-out $(export-objs), $(obj-y))) 定义了 L_OBJS 的生成方式:在 obj-y 的列表中过滤掉 export-objs(tc.o),然后排序并去除重复的文件名。这里使用到了 GNU Make 的一些特殊功能,具体的含义可参考 Make 的文档(info make)。

  d) include $(TOPDIR)/Rules.make

  3. 配置文件

  3.1 配置功能概述

  除了 Makefile 的编写,另外一个重要的工作就是把新功能加入到 Linux 的配置选项中,提供此项功能的说明,让用户有机会选择此项功能。所有的这些都需要在 config.in 文件中用配置语言来编写配置脚本,

  在 Linux 内核中,配置命令有多种方式:

  配置命令 解释脚本

  Make config, make oldconfig scripts/Configure

  Make menuconfig scripts/Menuconfig

  Make xconfig scripts/tkparse

  以字符界面配置(make config)为例,顶层 Makefile 调用 scripts/Configure, 按照 arch/arm/config.in 来进行配置。命令执行完后产生文件 .config,其中保存着配置信息。下一次再做 make config 将产生新的 .config 文件,原 .config 被改名为 .config.old

 

3.2 配置语言

  1) 顶层菜单

  mainmenu_name /prompt/ /prompt/ 是用'或"包围的字符串,'与"的区别是'…'中可使用$引用变量的值。mainmenu_name 设置最高层菜单的名字,它只在 make xconfig 时才会显示。

  2) 询问语句

  bool /prompt/ /symbol/

  hex /prompt/ /symbol/ /word/

  int /prompt/ /symbol/ /word/

  string /prompt/ /symbol/ /word/

  tristate /prompt/ /symbol/

  询问语句首先显示一串提示符 /prompt/,等待用户输入,并把输入的结果赋给 /symbol/ 所代表的配置变量。不同的询问语句的区别在于它们接受的输入数据类型不同,比如 bool 接受布尔类型( y 或 n ),hex 接受 16 进制数据。有些询问语句还有第三个参数 /word/,用来给出缺省值。

------分隔线----------------------------
标签(Tag):Ubuntu Linux Android 操作系统 Unix fedora
------分隔线----------------------------
推荐内容
猜你感兴趣