6) 配置变量CONFIG_*
  .config 文件中有许多的配置变量等式,用来说明用户配置的结果。例如 CONFIG_MODULES=y 表明用户选择了 Linux 内核的模块功能。
  .config 被顶层 Makefile 包含后,形成许多的配置变量,每个配置变量具有确定的值:y 表示本编译选项对应的内核代码被静态编译进 Linux 内核;m 表示本编译选项对应的内核代码被编译成模块;n 表示不选择此编译选项;如果根本没有选择,那么配置变量的值为空。
  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 结尾。
  子目录 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(filter?out(obj-y), $(obj-m))
# Translate to Rules.make lists.
L_TARGET:= tc.a
L_OBJS       := (sort(sort(filter-out (export?objs),(export?objs),(obj-y)))
LX_OBJS      := (sort(sort(filter     (export?objs),(export?objs),(obj-y)))
M_OBJS       := (sort(sort(filter-out (export?objs),(export?objs),(obj-m)))
MX_OBJS      := (sort(sort(filter     (export?objs),(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(sort(filter-out (export?objs),(export?objs),(obj-y))) 定义了 L_OBJS 的生成方式:在 obj-y 的列表中过滤掉 export-objs(tc.o),然后排序并去除重复的文件名。这里使用到了 GNU Make 的一些特殊功能,具体的含义可参考 Make 的文档(info make)。
  d) include $(TOPDIR)/Rules.make