转自:http://www.cnblogs.com/Daniel-G/p/3286614.html

随着 Linux 操作系统的广泛应用,特别是 Linux 在嵌入式领域的发展,越来越多的人开始投身到 Linux 内核级的开发中。面对日益庞大的 Linux 内核源代码,开发者在完成自己的内核代码后,都将面临着同样的问题,即如何将源代码融入到 Linux 内核中,增加相应的 Linux 配置选项,并最终被编译进 Linux 内核。这就需要了解 Linux 的内核配置系统。

  1. 众所周知,Linux 内核是由分布在全球的 Linux 爱好者共同开发的,Linux 内核每天都面临着许多新的变化。但是,Linux 内核的组织并没有出现混乱的现象,反而显得非常的简洁,而且具有很好的扩展性,开发人员可以很方便的向 Linux 内核中增加新的内容。原因之一就是 Linux 采用了模块化的内核配置系统,从而保证了内核的扩展性。
  2. 本文首先分析了 Linux 内核中的配置系统结构,然后,解释了 Makefile 和配置文件的格式以及配置语句的含义,最后,通过一个简单的例子--TEST Driver,具体说明如何将自行开发的代码加入到 Linux 内核中。在下面的文章中,不可能解释所有的功能和命令,只对那些常用的进行解释,至于那些没有讨论到的,请读者参考后面的参考文献。
  3. 配置系统的基本结构
  4. Linux内核的配置系统由三个部分组成,分别是:
  5. Makefile:分布在 Linux 内核源代码中的 Makefile,定义 Linux 内核的编译规则;
  6. 配置文件(config.in):给用户提供配置选择的功能;
  7. 配置工具:包括配置命令解释器(对配置脚本中使用的配置命令进行解释)和配置用户界面(提供基于字符界面、基于 Ncurses 图形界面以及基于 Xwindows 图形界面的用户配置界面,各自对应于 Make configMake menuconfig make xconfig)。
  8. 这些配置工具都是使用脚本语言,如 Tcl/TKPerl 编写的(也包含一些用 C 编写的代码)。本文并不是对配置系统本身进行分析,而是介绍如何使用配置系统。所以,除非是配置系统的维护者,一般的内核开发者无须了解它们的原理,只需要知道如何编写 Makefile 和配置文件就可以。所以,在本文中,我们只对 Makefile 和配置文件进行讨论。另外,凡是涉及到与具体 CPU 体系结构相关的内容,我们都以 ARM 为例,这样不仅可以将讨论的问题明确化,而且对内容本身不产生影响。
  9.  
  10. Makefile
  11. 2.1 Makefile 概述
  12. Makefile 的作用是根据配置的情况,构造出需要编译的源文件列表,然后分别编译,并把目标代码链接到一起,最终形成 Linux 内核二进制文件。
  13. 由于 Linux 内核源代码是按照树形结构组织的,所以 Makefile 也被分布在目录树中。Linux 内核中的 Makefile 以及与 Makefile 直接相关的文件有:
  14. Makefile:顶层 Makefile,是整个内核配置、编译的总体控制文件。
  15. .config:内核配置文件,包含由用户选择的配置选项,用来存放内核配置后的结果(如 make config)。
  16. arch/*/Makefile:位于各种 CPU 体系目录下的 Makefile,如 arch/arm/Makefile,是针对特定平台的 Makefile。
  17. 各个子目录下的 Makefile:比如 drivers/Makefile,负责所在子目录下源代码的管理。
  18. Rules.make:规则文件,被所有的 Makefile 使用。
  19. 用户通过 make config 配置后,产生了 .config。顶层 Makefile 读入 .config 中的配置选择。顶层 Makefile 有两个主要的任务:产生 vmlinux 文件和内核模块(module)。为了达到此目的,顶层 Makefile 递归的进入到内核的各个子目录中,分别调用位于这些子目录中的 Makefile。至于到底进入哪些子目录,取决于内核的配置。在顶层 Makefile 中,有一句:include arch/$(ARCH)/Makefile,包含了特定 CPU 体系结构下的 Makefile,这个 Makefile 中包含了平台相关的信息。
  20. 位于各个子目录下的 Makefile 同样也根据 .config 给出的配置信息,构造出当前配置下需要的源文件列表,并在文件的最后有 include $(TOPDIR)/Rules.make。
  21. Rules.make 文件起着非常重要的作用,它定义了所有 Makefile 共用的编译规则。比如,如果需要将本目录下所有的 c 程序编译成汇编代码,需要在 Makefile 中有以下的编译规则:
  22. %.s: %.c
  23. $(CC) $(CFLAGS) -S $< -o $@
  24. 有很多子目录下都有同样的要求,就需要在各自的 Makefile 中包含此编译规则,这会比较麻烦。而 Linux 内核中则把此类的编译规则统一放置到 Rules.make 中,并在各自的 Makefile 中包含进了 Rules.make(include Rules.make),这样就避免了在多个 Makefile 中重复同样的规则。对于上面的例子,在 Rules.make 中对应的规则为:
  25. %.s: %.c
  26. $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$(*F)) $(CFLAGS_$@) -S $< -o $@
  27. 2.2 Makefile 中的变量
  28. 顶层 Makefile 定义并向环境中输出了许多变量,为各个子目录下的 Makefile 传递一些信息。有些变量,比如 SUBDIRS,不仅在顶层 Makefile 中定义并且赋初值,而且在 arch/*/Makefile 还作了扩充。
  29. 常用的变量有以下几类:
  30. 版本信息
  31. 版本信息有:VERSIONPATCHLEVEL, SUBLEVEL, EXTRAVERSIONKERNELRELEASE。版本信息定义了当前内核的版本,比如 VERSION=,PATCHLEVEL=,SUBLEVEL=,EXATAVERSION=-rmk7,它们共同构成内核的发行版本KERNELRELEASE2.4.-rmk7
  32. CPU 体系结构:ARCH
  33. 在顶层 Makefile 的开头,用 ARCH 定义目标 CPU 的体系结构,比如 ARCH:=arm 等。许多子目录的 Makefile 中,要根据 ARCH 的定义选择编译源文件的列表。
  34. 路径信息:TOPDIR, SUBDIRS
  35. TOPDIR 定义了 Linux 内核源代码所在的根目录。例如,各个子目录下的 Makefile 通过 $(TOPDIR)/Rules.make 就可以找到 Rules.make 的位置。
  36. SUBDIRS 定义了一个目录列表,在编译内核或模块时,顶层 Makefile 就是根据 SUBDIRS 来决定进入哪些子目录。SUBDIRS 的值取决于内核的配置,在顶层 Makefile SUBDIRS 赋值为 kernel drivers mm fs net ipc lib;根据内核的配置情况,在 arch/*/Makefile 中扩充了 SUBDIRS 的值,参见4)中的例子。
  37. 4) 内核组成信息:HEAD, CORE_FILES, NETWORKS, DRIVERS, LIBS
  38. Linux 内核文件 vmlinux 是由以下规则产生的:
  39. vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs
  40. $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \
  41. --start-group \
  42. $(CORE_FILES) \
  43. $(DRIVERS) \
  44. $(NETWORKS) \
  45. $(LIBS) \
  46. --end-group \
  47. -o vmlinux
  48.  
  49. 可以看出,vmlinux 是由 HEAD、main.o、version.o、CORE_FILES、DRIVERS、NETWORKS 和 LIBS 组成的。这些变量(如 HEAD)都是用来定义连接生成 vmlinux 的目标文件和库文件列表。其中,HEAD在arch/*/Makefile 中定义,用来确定被最先链接进 vmlinux 的文件列表。比如,对于 ARM 系列的 CPUHEAD 定义为:
  50. HEAD := arch/arm/kernel/head-$(PROCESSOR).o \
  51. arch/arm/kernel/init_task.o
  52.  
  53. 表明 head-$(PROCESSOR).o init_task.o 需要最先被链接到 vmlinux 中。PROCESSOR armv armo,取决于目标 CPU CORE_FILESNETWORKDRIVERS LIBS 在顶层 Makefile 中定义,并且由 arch/*/Makefile 根据需要进行扩充。 CORE_FILES 对应着内核的核心文件,有 kernel/kernel.o,mm/mm.o,fs/fs.o,ipc/ipc.o,可以看出,这些是组成内核最为重要的文件。同时,arch/arm/Makefile 对 CORE_FILES 进行了扩充:
  54. # arch/arm/Makefile
  55. # If we have a machine-specific directory, then include it in the build.
  56. MACHDIR := arch/arm/mach-$(MACHINE)
  57. ifeq ($(MACHDIR),$(wildcard $(MACHDIR)))
  58. SUBDIRS += $(MACHDIR)
  59. CORE_FILES := $(MACHDIR)/$(MACHINE).o $(CORE_FILES)
  60. endif
  61. HEAD := arch/arm/kernel/head-$(PROCESSOR).o \
  62. arch/arm/kernel/init_task.o
  63. SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpe
  64. CORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES)
  65. LIBS := arch/arm/lib/lib.a $(LIBS)
  66.  
  67. 5) 编译信息:CPP, CC, AS, LD, AR,CFLAGS,LINKFLAGS
  68. 在 Rules.make 中定义的是编译的通用规则,具体到特定的场合,需要明确给出编译环境,编译环境就是在以上的变量中定义的。针对交叉编译的要求,定义了 CROSS_COMPILE。比如:
  69. CROSS_COMPILE = arm-linux-
  70. CC = $(CROSS_COMPILE)gcc
  71. LD = $(CROSS_COMPILE)ld
  72. ......
  73.  
  74. CROSS_COMPILE 定义了交叉编译器前缀 arm-linux-,表明所有的交叉编译工具都是以 arm-linux- 开头的,所以在各个交叉编译器工具之前,都加入了 $(CROSS_COMPILE),以组成一个完整的交叉编译工具文件名,比如 arm-linux-gcc。
  75. CFLAGS 定义了传递给 C 编译器的参数。
  76. LINKFLAGS 是链接生成 vmlinux 时,由链接器使用的参数。LINKFLAGS 在 arm/*/Makefile 中定义,比如:
  77. # arch/arm/Makefile
  78. LINKFLAGS :=-p -X -T arch/arm/vmlinux.lds
  79.  
  80. 配置变量CONFIG_*
  81. .config 文件中有许多的配置变量等式,用来说明用户配置的结果。例如 CONFIG_MODULES=y 表明用户选择了 Linux 内核的模块功能。
  82. .config 被顶层 Makefile 包含后,就形成许多的配置变量,每个配置变量具有确定的值:y 表示本编译选项对应的内核代码被静态编译进 Linux 内核;m 表示本编译选项对应的内核代码被编译成模块;n 表示不选择此编译选项;如果根本就没有选择,那么配置变量的值为空。
  83. 2.3 Rules.make 变量
  84. 前面讲过,Rules.make 是编译规则文件,所有的 Makefile 中都会包括 Rules.makeRules.make 文件定义了许多变量,最为重要是那些编译、链接列表变量。
  85. O_OBJSL_OBJSOX_OBJSLX_OBJS:本目录下需要编译进 Linux 内核 vmlinux 的目标文件列表,其中 OX_OBJS LX_OBJS 中的 "X" 表明目标文件使用了 EXPORT_SYMBOL 输出符号。
  86. M_OBJSMX_OBJS:本目录下需要被编译成可装载模块的目标文件列表。同样,MX_OBJS 中的 "X" 表明目标文件使用了 EXPORT_SYMBOL 输出符号。
  87. O_TARGETL_TARGET:每个子目录下都有一个 O_TARGET L_TARGETRules.make 首先从源代码编译生成 O_OBJS OX_OBJS 中所有的目标文件,然后使用 $(LD) -r 把它们链接成一个 O_TARGET L_TARGETO_TARGET .o 结尾,而 L_TARGET .a 结尾。
  88. 2.4 子目录 Makefile
  89. 子目录 Makefile 用来控制本级目录以下源代码的编译规则。我们通过一个例子来讲解子目录 Makefile 的组成:
  90. #
  91. # Makefile for the linux kernel.
  92. #
  93. # All of the (potential) objects that export symbols.
  94. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
  95. export-objs := tc.o
  96. # Object file lists.
  97. obj-y :=
  98. obj-m :=
  99. obj-n :=
  100. obj- :=
  101. obj-$(CONFIG_TC) += tc.o
  102. obj-$(CONFIG_ZS) += zs.o
  103. obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o
  104. # Files that are both resident and modular: remove from modular.
  105. obj-m := $(filter-out $(obj-y), $(obj-m))
  106. # Translate to Rules.make lists.
  107. L_TARGET := tc.a
  108. L_OBJS := $(sort $(filter-out $(export-objs), $(obj-y)))
  109. LX_OBJS := $(sort $(filter $(export-objs), $(obj-y)))
  110. M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
  111. MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
  112. include $(TOPDIR)/Rules.make
  113.  
  114. a) 注释
  115. Makefile 的说明和解释,由#开始。
  116. b) 编译目标定义
  117. 类似于 obj-$(CONFIG_TC) += tc.o 的语句是用来定义编译的目标,是子目录 Makefile 中最重要的部分。编译目标定义那些在本子目录下,需要编译到 Linux 内核中的目标文件列表。为了只在用户选择了此功能后才编译,所有的目标定义都融合了对配置变量的判断。
  118. 前面说过,每个配置变量取值范围是:ynm 和空,obj-$(CONFIG_TC) 分别对应着 obj-yobj-nobj-mobj-。如果 CONFIG_TC 配置为 y,那么 tc.o 就进入了 obj-y 列表。obj-y 为包含到 Linux 内核 vmlinux 中的目标文件列表;obj-m 为编译成模块的目标文件列表;obj-n obj- 中的文件列表被忽略。配置系统就根据这些列表的属性进行编译和链接。
  119. export-objs 中的目标文件都使用了 EXPORT_SYMBOL() 定义了公共的符号,以便可装载模块使用。在 tc.c 文件的最后部分,有 "EXPORT_SYMBOL(search_tc_card);",表明 tc.o 有符号输出。
  120. 这里需要指出的是,对于编译目标的定义,存在着两种格式,分别是老式定义和新式定义。老式定义就是前面 Rules.make 使用的那些变量,新式定义就是 obj-yobj-mobj-n obj-。Linux 内核推荐使用新式定义,不过由于 Rules.make 不理解新式定义,需要在 Makefile 中的适配段将其转换成老式定义。
  121. c) 适配段
  122. 适配段的作用是将新式定义转换成老式定义。在上面的例子中,适配段就是将 obj-y obj-m 转换成 Rules.make 能够理解的 L_TARGETL_OBJSLX_OBJSM_OBJSMX_OBJS
  123. L_OBJS := $(sort $(filter-out $(export-objs), $(obj-y))) 定义了 L_OBJS 的生成方式:在 obj-y 的列表中过滤掉 export-objstc.o),然后排序并去除重复的文件名。这里使用到了 GNU Make 的一些特殊功能,具体的含义可参考 Make 的文档(info make)。
  124. d) include $(TOPDIR)/Rules.make
  125.  
  126. 配置文件
  127. 3.1 配置功能概述
  128. 除了 Makefile 的编写,另外一个重要的工作就是把新功能加入到 Linux 的配置选项中,提供此项功能的说明,让用户有机会选择此项功能。所有的这些都需要在 config.in 文件中用配置语言来编写配置脚本,
  129. Linux 内核中,配置命令有多种方式:
  130. 配置命令 解释脚本
  131. Make config, make oldconfig scripts/Configure
  132. Make menuconfig scripts/Menuconfig
  133. Make xconfig scripts/tkparse
  134. 以字符界面配置(make config)为例,顶层 Makefile 调用 scripts/Configure 按照 arch/arm/config.in 来进行配置。命令执行完后产生文件 .config,其中保存着配置信息。下一次再做 make config 将产生新的 .config 文件,原 .config 被改名为 .config.old
  135. 3.2 配置语言
  136. 顶层菜单
  137. mainmenu_name /prompt/ /prompt/ 是用'或"包围的字符串,'"的区别是'…'中可使用$引用变量的值。mainmenu_name 设置最高层菜单的名字,它只在 make xconfig 时才会显示。
  138. ) 询问语句
  139. bool /prompt/ /symbol/
  140. hex /prompt/ /symbol/ /word/
  141. int /prompt/ /symbol/ /word/
  142. string /prompt/ /symbol/ /word/
  143. tristate /prompt/ /symbol/
  144.  
  145. 询问语句首先显示一串提示符 /prompt/,等待用户输入,并把输入的结果赋给 /symbol/ 所代表的配置变量。不同的询问语句的区别在于它们接受的输入数据类型不同,比如 bool 接受布尔类型( y 或 n ),hex 接受 进制数据。有些询问语句还有第三个参数 /word/,用来给出缺省值。
  146. ) 定义语句
  147. define_bool /symbol/ /word/
  148. define_hex /symbol/ /word/
  149. define_int /symbol/ /word/
  150. define_string /symbol/ /word/
  151. define_tristate /symbol/ /word/
  152.  
  153. 不同于询问语句等待用户输入,定义语句显式的给配置变量 /symbol/ 赋值 /word/。
  154. ) 依赖语句
  155.  
  156. dep_bool /prompt/ /symbol/ /dep/ ...
  157. dep_mbool /prompt/ /symbol/ /dep/ ...
  158. dep_hex /prompt/ /symbol/ /word/ /dep/ ...
  159. dep_int /prompt/ /symbol/ /word/ /dep/ ...
  160. dep_string /prompt/ /symbol/ /word/ /dep/ ...
  161. dep_tristate /prompt/ /symbol/ /dep/ ...
  162.  
  163. 与询问语句类似,依赖语句也是定义新的配置变量。不同的是,配置变量/symbol/的取值范围将依赖于配置变量列表/dep/ …。这就意味着:被定义的配置变量所对应功能的取舍取决于依赖列表所对应功能的选择。以dep_bool为例,如果/dep/ …列表的所有配置变量都取值y,则显示/prompt/,用户可输入任意的值给配置变量/symbol/,但是只要有一个配置变量的取值为n,则/symbol/被强制成n。
  164. 不同依赖语句的区别在于它们由依赖条件所产生的取值范围不同。
  165. ) 选择语句
  166. choice /prompt/ /word/ /word/
  167.  
  168. choice 语句首先给出一串选择列表,供用户选择其中一种。比如 Linux for ARM 支持多种基于 ARM core 的 CPU,Linux 使用 choice 语句提供一个 CPU 列表,供用户选择:
  169.  
  170. choice 'ARM system type' \
  171. "Anakin CONFIG_ARCH_ANAKIN \
  172. Archimedes/A5000 CONFIG_ARCH_ARCA5K \
  173. Cirrus-CL-PS7500FE CONFIG_ARCH_CLPS7500 \
  174. ……
  175. SA1100-based CONFIG_ARCH_SA1100 \
  176. Shark CONFIG_ARCH_SHARK" RiscPC
  177.  
  178. Choice 首先显示 /prompt/,然后将 /word/ 分解成前后两个部分,前部分为对应选择的提示符,后部分是对应选择的配置变量。用户选择的配置变量为 y,其余的都为 n。
  179. ) if语句
  180. if [ /expr/ ] ; then
  181. /statement/
  182. ...
  183. fi
  184.  
  185. if [ /expr/ ] ; then
  186. /statement/
  187. ...
  188. else
  189. /statement/
  190. ...
  191. fi
  192.  
  193. if 语句对配置变量(或配置变量的组合)进行判断,并作出不同的处理。判断条件 /expr/ 可以是单个配置变量或字符串,也可以是带操作符的表达式。操作符有:=,!=,-o,-a 等。
  194. ) 菜单块(menu block)语句
  195. mainmenu_option next_comment
  196. comment '…..'

  197. endmenu
  198.  
  199. 引入新的菜单。在向内核增加新的功能后,需要相应的增加新的菜单,并在新菜单下给出此项功能的配置选项。Comment 后带的注释就是新菜单的名称。所有归属于此菜单的配置选项语句都写在 comment 和 endmenu 之间。
  200. ) Source 语句
  201. source /word/
  202. /word/ 是文件名,source 的作用是调入新的文件。
  203. 3.3 缺省配置
  204. Linux 内核支持非常多的硬件平台,对于具体的硬件平台而言,有些配置就是必需的,有些配置就不是必需的。另外,新增加功能的正常运行往往也需要一定的先决条件,针对新功能,必须作相应的配置。因此,特定硬件平台能够正常运行对应着一个最小的基本配置,这就是缺省配置。
  205. Linux 内核中针对每个 ARCH 都会有一个缺省配置。在向内核代码增加了新的功能后,如果新功能对于这个 ARCH 是必需的,就要修改此 ARCH 的缺省配置。修改方法如下(在 Linux 内核根目录下):
  206. 备份 .config 文件
  207. cp arch/arm/deconfig .config
  208. 修改 .config
  209. cp .config arch/arm/deconfig
  210. 恢复 .config
  211. 如果新增的功能适用于许多的 ARCH,只要针对具体的 ARCH,重复上面的步骤就可以了。
  212. 3.4 help file
  213. 大家都有这样的经验,在配置 Linux 内核时,遇到不懂含义的配置选项,可以查看它的帮助,从中可得到选择的建议。下面我们就看看如何给给一个配置选项增加帮助信息。
  214. 所有配置选项的帮助信息都在 Documentation/Configure.help 中,它的格式为:
  215. <description>
  216. <variable name>
  217. <help file>
  218.  
  219. <description> 给出本配置选项的名称,<variable name> 对应配置变量,<help file> 对应配置帮助信息。在帮助信息中,首先简单描述此功能,其次说明选择了此功能后会有什么效果,不选择又有什么效果,最后,不要忘了写上"如果不清楚,选择 N(或者)Y",给不知所措的用户以提示。
  220.  
  221. . 实例
  222. 对于一个开发者来说,将自己开发的内核代码加入到 Linux 内核中,需要有三个步骤。首先确定把自己开发代码放入到内核的位置;其次,把自己开发的功能增加到 Linux 内核的配置选项中,使用户能够选择此功能;最后,构建子目录 Makefile,根据用户的选择,将相应的代码编译到最终生成的 Linux 内核中去。下面,我们就通过一个简单的例子--test driver,结合前面学到的知识,来说明如何向 Linux 内核中增加新的功能。
  223. 4.1 目录结构
  224. test driver 放置在 drivers/test/ 目录下:
  225. $cd drivers/test
  226. $tree
  227. .
  228. |-- Config.in
  229. |-- Makefile
  230. |-- cpu
  231. | |-- Makefile
  232. | `-- cpu.c
  233. |-- test.c
  234. |-- test_client.c
  235. |-- test_ioctl.c
  236. |-- test_proc.c
  237. |-- test_queue.c
  238. `-- test
  239. |-- Makefile
  240. `-- test.c
  241.  
  242. 4.2 配置文件
  243. ) drivers/test/Config.in
  244. #
  245. # TEST driver configuration
  246. #
  247. mainmenu_option next_comment
  248. comment 'TEST Driver'
  249. bool 'TEST support' CONFIG_TEST
  250. if [ "$CONFIG_TEST" = "y" ]; then
  251. tristate 'TEST user-space interface' CONFIG_TEST_USER
  252. bool 'TEST CPU ' CONFIG_TEST_CPU
  253. fi
  254. endmenu
  255.  
  256. 由于 test driver 对于内核来说是新的功能,所以首先创建一个菜单 TEST Driver。然后,显示 "TEST support",等待用户选择;接下来判断用户是否选择了 TEST Driver,如果是(CONFIG_TEST=y),则进一步显示子功能:用户接口与 CPU 功能支持;由于用户接口功能可以被编译成内核模块,所以这里的询问语句使用了 tristate(因为 tristate 的取值范围包括 y、n 和 m,m 就是对应着模块)。
  257. ) arch/arm/config.in
  258. 在文件的最后加入:source drivers/test/Config.in,将 TEST Driver 子功能的配置纳入到 Linux 内核的配置中。
  259. 4.3 Makefile
  260. )drivers/test/Makefile
  261.  
  262. # drivers/test/Makefile
  263. #
  264. # Makefile for the TEST.
  265. #
  266. SUB_DIRS :=
  267. MOD_SUB_DIRS := $(SUB_DIRS)
  268. ALL_SUB_DIRS := $(SUB_DIRS) cpu
  269. L_TARGET := test.a
  270. export-objs := test.o test_client.o
  271. obj-$(CONFIG_TEST) += test.o test_queue.o test_client.o
  272. obj-$(CONFIG_TEST_USER) += test_ioctl.o
  273. obj-$(CONFIG_PROC_FS) += test_proc.o
  274. subdir-$(CONFIG_TEST_CPU) += cpu
  275. include $(TOPDIR)/Rules.make
  276. clean:
  277. for dir in $(ALL_SUB_DIRS); do make -C $$dir clean; done
  278. rm -f *.[oa] .*.flags
  279.  
  280. drivers/test 目录下最终生成的目标文件是 test.a。在 test.c 和 test-client.c 中使用了 EXPORT_SYMBOL 输出符号,所以 test.o 和 test-client.o 位于 export-objs 列表中。然后,根据用户的选择(具体来说,就是配置变量的取值),构建各自对应的 obj-* 列表。由于 TEST Driver 中包一个子目录 cpu,当 CONFIG_TEST_CPU=y(即用户选择了此功能)时,需要将 cpu 目录加入到 subdir-y 列表中。
  281. )drivers/test/cpu/Makefile
  282.  
  283. # drivers/test/test/Makefile
  284. #
  285. # Makefile for the TEST CPU
  286. #
  287. SUB_DIRS :=
  288. MOD_SUB_DIRS := $(SUB_DIRS)
  289. ALL_SUB_DIRS := $(SUB_DIRS)
  290. L_TARGET := test_cpu.a
  291. obj-$(CONFIG_test_CPU) += cpu.o
  292. include $(TOPDIR)/Rules.make
  293. clean:
  294. rm -f *.[oa] .*.flags
  295.  
  296. )drivers/Makefile
  297. ……
  298. subdir-$(CONFIG_TEST) += test
  299. ……
  300. include $(TOPDIR)/Rules.make
  301.  
  302. 在 drivers/Makefile 中加入 subdir-$(CONFIG_TEST)+= test,使得在用户选择 TEST Driver 功能后,内核编译时能够进入 test 目录。
  303. )Makefile
  304. ……
  305. DRIVERS-$(CONFIG_PLD) += drivers/pld/pld.o
  306. DRIVERS-$(CONFIG_TEST) += drivers/test/test.a
  307. DRIVERS-$(CONFIG_TEST_CPU) += drivers/test/cpu/test_cpu.a
  308. DRIVERS := $(DRIVERS-y)
  309. ……
  310.  
  311. 在顶层 Makefile 中加入 DRIVERS-$(CONFIG_TEST) += drivers/test/test.a 和 DRIVERS-$(CONFIG_TEST_CPU) += drivers/test/cpu/test_cpu.a。如何用户选择了 TEST Driver,那么 CONFIG_TEST 和 CONFIG_TEST_CPU 都是 y,test.a 和 test_cpu.a 就都位于 DRIVERS-y 列表中,然后又被放置在 DRIVERS 列表中。在前面曾经提到过,Linux 内核文件 vmlinux 的组成中包括 DRIVERS,所以 test.a 和 test_cpu.a 最终可被链接到 vmlinux 中。

linux源码Makefile详解(完整)【转】的更多相关文章

  1. linux源码Makefile详解(完整)

    转自:http://www.cnblogs.com/Daniel-G/p/3286614.html 随着 Linux 操作系统的广泛应用,特别是 Linux 在嵌入式领域的发展,越来越多的人开始投身到 ...

  2. linux源码Makefile详解

    1.Makefile的作用 (1)决定编译哪些文件 (2)怎样编译这些文件 (3)怎样连接这些文件,最重要的是它们的顺序如何 2.Linux内核Makefile分类 ***************** ...

  3. linux 源码安装详解

    ./configure是用来检测你的安装平台的目标特征的.比如它会检测你是不是有CC或GCC,并不是需要CC或GCC,它是个shell脚本.make是用来编译的,它从Makefile中读取指令,然后编 ...

  4. Hadoop3.1.1源码Client详解 : Packet入队后消息系统运作之ResponseProcessor(ACK接收)

    该系列总览: Hadoop3.1.1架构体系——设计原理阐述与Client源码图文详解 : 总览 紧接着上一篇文章: Hadoop3.1.1源码Client详解 : Packet入队后消息系统运作之D ...

  5. NopCommerce源码架构详解--初识高性能的开源商城系统cms

    很多人都说通过阅读.学习大神们高质量的代码是提高自己技术能力最快的方式之一.我觉得通过阅读NopCommerce的源码,可以从中学习很多企业系统.软件开发的规范和一些新的技术.技巧,可以快速地提高我们 ...

  6. NopCommerce源码架构详解

    NopCommerce源码架构详解--初识高性能的开源商城系统cms   很多人都说通过阅读.学习大神们高质量的代码是提高自己技术能力最快的方式之一.我觉得通过阅读NopCommerce的源码,可以从 ...

  7. Nop--NopCommerce源码架构详解专题目录

    最近在研究外国优秀的ASP.NET mvc电子商务网站系统NopCommerce源码架构.这个系统无论是代码组织结构.思想及分层都值得我们学习.对于没有一定开发经验的人要完全搞懂这个源码还是有一定的难 ...

  8. Hadoop3.1.1架构体系——设计原理阐述与Client源码图文详解 : 总览

    一.设计原理 1.Hadoop架构: 流水线(PipeLine) 2.Hadoop架构: HDFS中数据块的状态及其切换过程,GS与BGS 3.Hadoop架构: 关于Recovery (Lease ...

  9. Hadoop3.1.1源码Client详解 : 写入准备-RPC调用与流的建立

    该系列总览: Hadoop3.1.1架构体系——设计原理阐述与Client源码图文详解 : 总览 关于RPC(Remote Procedure Call),如果没有概念,可以参考一下RMI(Remot ...

随机推荐

  1. [BS] 小知识点总结-03

    1.Autolayout中“constrain to margins” Autolayout中的页面边距的问题ios8以后的UIView增加了layoutMargins属性,在Storyboard/I ...

  2. 从AsyncTask中获取数据的问题

    public class GetData extends AsyncTask<String, Void, String> { DataDownloadListener dataDownlo ...

  3. C# GridControl 行背景颜色

    使用C# DevExpress_gridControl 行号行样式显示行背景颜色,必须取消自动变换行色属性 取消Focus变色,属性为OptionSelection--EnableAppearance ...

  4. Java多线程 wait, notify 和 notifyAll

    Java的Object类 public class Object { public final native void notify(); public final native void notif ...

  5. Redhat linux 挂载命令mount

    命令格式: mount [-t vfstype] [-o options] device dir 其中: 1.-t vfstype 指定文件系统的类型,通常不必指定.mount 会自动选择正确的类型. ...

  6. storm安装

    官方安装地址:http://storm.apache.org/releases/1.0.2/Setting-up-a-Storm-cluster.html storm集群的三个角色 Nimbus.Su ...

  7. nginx 日志分析

    Nginx中日志文件的格式在nginx.conf中定义,其默认格式如下: #vim /usr/local/nginx/conf/nginx.conf          log_format acces ...

  8. Oracle 10G如何从recovery catalog中Unregister目标数据库

    从10g开始,RMAN简化了unregister目标数据库的步骤 方法1: $rman target system/oracle@test catalog rman/rman@catadb rman& ...

  9. Android Bundle类

    根据google官方的文档(http://developer.android.com/reference/android/os/Bundle.html) Bundle类是一个key-value对,“A ...

  10. css 滑动按钮样式

    <div class="pub_switch_box"> <input type="checkbox" id="pub_switch ...