日期:2014-05-16  浏览次数:20709 次

Linux内核Makefile文件

Linux内核Makefile文件
2011年06月06日
  本文是/Documentation/kbuild/makefiles.txt的中文译稿
  Linux内核Makefiles
  本篇文章描述了Linux内核Makefiles。
  === 目录
  === 1 概述
  === 2 角色分工
  === 3 内核编译文件
  --- 3.1 目标定义
  --- 3.2 内嵌对象 - obj-y
  --- 3.3 可加载模块 - obj-m
  --- 3.4 导出符号
  --- 3.5 库文件 - lib-y
  --- 3.6 目录递归
  --- 3.7 编译标记
  --- 3.8 命令依赖
  --- 3.9 依赖关系
  --- 3.10 特殊规则
  --- 3.11 $(CC)支持功能
  === 4 辅助程序
  --- 4.1 简单辅助程序
  --- 4.2 组合辅助程序
  --- 4.3 定义共享库
  --- 4.4 C++语言使用方法
  --- 4.5 辅助程序编译控制选项
  --- 4.6 何时建立辅助程序
  --- 4.7 使用hostprogs-$(CONFIG_FOO)
  === 5 编译清除机制
  === 6 体系Makefile文件
  --- 6.1 变量设置
  --- 6.2 增加预设置项
  --- 6.3 目录表
  --- 6.4 引导映像
  --- 6.5 编译非内核目标
  --- 6.6 编译引导映像命令
  --- 6.7 定制编译命令
  --- 6.8 预处理连接脚本
  === 7 Kbuild变量
  === 8 Makefile语言
  === 9 Credits
  === 10 TODO
  === 1 概述
  Makefile包括五部分:
  Makefile                 顶层Makefile文件
  .config                  内核配置文件
  arch/$(ARCH)/Makefile    机器体系Makefile文件
  scripts/Makefile.*       所有内核Makefiles共用规则
  kbuild Makefiles         其它Makefile文件
  通过内核配置操作产生.config文件,顶层Makefile文件读取该文件的配置。
  顶层Makefile文件负责产生两个主要的程序:vmlinux (内核image)和模块。顶层Makefile文件根据内核配置,通过递归编译内核代码树子目录建立这两个文件。顶层Makefile文件文本一个名为 arch/$(ARCH)/Makefile的机器体系Makefile文件。机器体系Makefile文件为顶层Makefile文件提供与机器相关的信息。
  每一个子目录有一个Makefile文件,子目录Makefile文件根据上级目录Makefile文件命令启动编译。这些Makefile使用. config文件配置数据构建各种文件列表,并使用这些文件列表编译内嵌或模块目标文件。
  scripts/Makefile.*包含了所有的定义和规则,与Makefile文件一起编译出内核程序。
  === 2 角色分工
  人们与内核Makefile存在四种不同的关系:
  *用户* 用户使用"make menuconfig"或"make"命令编译内核。他们通常不读或编辑内核Makefile文件或其他源文件。
  *普通开发者* 普通开发者维护设备驱动程序、文件系统和网络协议代码,他们维护相关子系统的Makefile文件,因此他们需要内核Makefile文件整体性的一般知识和关于kbuild公共接口的详细知识。
  *体系开发者* 体系开发者关注一个整体的体系架构,比如sparc或者ia64。体系开发者既需要掌握关于体系的Makefile文件,也要熟悉内核Makefile文件。
  *内核开发者* 内核开发者关注内核编译系统本身。他们需要清楚内核Makefile文件的所有方面。
  本文档的读者对象是普通开发者和系统开发者。
  === 3 内核编译文件
  内核中大多数Makefile文件是使用kbuild基础架构的Makefile文件。本章介绍kbuild的Makefile中的语法。
  3.1节“目标定义”是一个快速导引,后面各章有详细介绍和实例。
  --- 3.1 目标定义
  目标定义是Makefile文件的主要部分(核心)。这些目标定义行定义了如何编译文件,特殊的兼容选项和递归子目录。
  最简单的Makefile文件只包含一行:
  Example:
  obj-y += foo.o
  这行告诉kbuild在该目录下名为foo.o的目标文件(object),foo.o通过编译foo.c或者foo.S而得到。
  如果foo.o编译成一个模块,则使用obj-m变量,因此常见写法如下:
  Example:
  obj-$(CONFIG_FOO) += foo.o
  $(CONFIG_FOO)可以代表y(built-in对象)或m(module对象)。如果CONFIG_FOO不是y或m,那么这个文件不会被编译和链接。
  --- 3.2 内嵌对象 - obj-y
  Makefile文件将为编译vmlinux的目标文件放在$(obj-y)列表中,这些列表依赖于内核配置。
  Kbuild编译所有的$(obj-y)文件,然后调用"$(LD) -r"合并这些文件到一个built-in.o文件中。built-in.o经过父Makefile文件链接到vmlinux。$(obj-y)中的文件 顺序很重要。列表中文件允许重复,文件第一次出现将被链接到built-in.o,后续出现该文件将被忽略。
  链接顺序之所以重要是因为一些函数在内核引导时将按照他们出现的顺序被调用,如函数(module_init() / __initcall)。所以要牢记改变链接顺序意味着也要改变SCSI控制器的检测顺序和重数磁盘。
  Example:
  #drivers/isdn/i4l/Makefile
  # 内核ISDN子系统和设备驱动程序Makefile
  # 每个配置项是一个文件列表
  obj-$(CONFIG_ISDN)         += isdn.o
  obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
  --- 3.3 可加载模块 - obj-m
  $(obj-m)表示对象文件(object files)编译成可加载的内核模块。
  一个模块可以通过一个源文件或几个源文件编译而成。Makefile只需简单地它们加到$(obj-m)。
  Example:
  #drivers/isdn/i4l/Makefile
  obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
  注意:在这个例子中$(CONFIG_ISDN_PPP_BSDCOMP)含义是'm'。
  如果内核模块通过几个源文件编译而成,使用以上同样的方法。
  Kbuild需要知道通过哪些文件编译模块,因此需要设置一个$(-objs)变量。
  Example:
  #dr