0

0

linux内核的配置系统由几部分组成

青灯夜游

青灯夜游

发布时间:2023-03-16 09:39:06

|

3144人浏览过

|

来源于php中文网

原创

linux内核的配置系统由3部分组成:1、Makefile,分布在Linux内核源代码根目录及各层目录中,定义Linux内核的编译规则;2、配置文件(config.in),给用户提供配置选择的能力;3、配置工具,包括配置命令解释器(对配置脚本中使用的配置命令进行解释)和配置用户界面。

linux内核的配置系统由几部分组成

本教程操作环境:linux7.3系统、Dell G3电脑。

Linux内核的配置系统由三部分组成,它们分别是:Makefile、配置文件( config.in )、配置工具。

  • Makefile:分布在 Linux 内核源代码根目录及各层目录中,定义 Linux 内核的编译规则;

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

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

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

Makefile

Makefile概述

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

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

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

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

  • arch/*/Makefile:位于各种 CPU 体系目录下的 Makefile,如 arch/arm/Makefile,是针对特定平台的 Makefile。 

  • 各个子目录下的 Makefile:比如 drivers/Makefile,负责所在子目录下源代码的管理。 

  • Rules.make:规则文件,被所有的 Makefile 使用。 

用户通过 make config 配置后,产生了 .config。顶层 Makefile 读入 .config 中的配置选择。顶层 Makefile 有两个主要的任务:产生 vmlinux 文件和内核模块(module)。为了达到此目的,顶层 Makefile 递归的进入到内核的各个子目录中,分别调用位于这些子目录中的 Makefile。至于到底进入哪些子目录,取决于内核的配置。在顶层 Makefile 中,有一句:include arch/$(ARCH)/Makefile,包含了特定 CPU 体系结构下的 Makefile,这个 Makefile 中包含了平台相关的信息。

位于各个子目录下的 Makefile 同样也根据 .config 给出的配置信息,构造出当前配置下需要的源文件列表,并在文件的最后有 include $(TOPDIR)/Rules.make。

Rules.make 文件起着非常重要的作用,它定义了所有 Makefile 共用的编译规则。比如,如果需要将本目录下所有的 c 程序编译成汇编代码,需要在 Makefile 中有以下的编译规则:

%.s: %.c
    (CC)  (CFLAGS) -S     o  @

有很多子目录下都有同样的要求,就需要在各自的 Makefile 中包含此编译规则,这会比较麻烦。而 Linux 内核中则把此类的编译规则统一放置到 Rules.make 中,并在各自的 Makefile 中包含进了 Rules.make(include Rules.make),这样就避免了在多个 Makefile 中重复同样的规则。对于上面的例子,在 Rules.make 中对应的规则为:

%.s: %.c
    (CC)  (CFLAGS)     (EXTRACFLAGS)  (CFLAGS_     (F))  (CFLAGS_     @)S  

Makefile中的变量

顶层 Makefile 定义并向环境中输出了许多变量,为各个子目录下的 Makefile 传递一些信息。有些变量,比如 SUBDIRS,不仅在顶层 Makefile 中定义并且赋初值,而且在 arch/*/Makefile 还作了扩充。

常用的变量有以下几类:

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;根据内核的配置情况,在 arch/*/Makefile 中扩充了 SUBDIRS 的值,参见4)中的例子。

4) 内核组成信息:HEAD, CORE_FILES, NETWORKS, DRIVERS, LIBS
Linux 内核文件 vmlinux 是由以下规则产生的:

vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs
    $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \
        --start-group \
        $(CORE_FILES) \
        $(DRIVERS) \
        $(NETWORKS) \
        $(LIBS) \
        --end-group \
        -o vmlinux

可以看出,vmlinux 是由 HEAD、main.o、version.o、CORE_FILES、DRIVERS、NETWORKS 和 LIBS 组成的。这些变量(如 HEAD)都是用来定义连接生成 vmlinux 的目标文件和库文件列表。其中,HEAD在arch/*/Makefile 中定义,用来确定被最先链接进 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 中定义,并且由 arch/*/Makefile 根据需要进行扩充。 CORE_FILES 对应着内核的核心文件,有 kernel/kernel.o,mm/mm.o,fs/fs.o,ipc/ipc.o,可以看出,这些是组成内核最为重要的文件。同时,arch/arm/Makefile 对 CORE_FILES 进行了扩充:

# arch/arm/Makefile
# If we have a machine-specific directory, then include it in the build.
MACHDIR         := arch/arm/mach-$(MACHINE)
ifeq ($(MACHDIR),$(wildcard $(MACHDIR)))
SUBDIRS         += $(MACHDIR)
CORE_FILES      := $(MACHDIR)/$(MACHINE).o $(CORE_FILES)
endif
HEAD            := arch/arm/kernel/head-$(PROCESSOR).o \
                   arch/arm/kernel/init_task.o
SUBDIRS         += arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpe
CORE_FILES      := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES)
LIBS            := arch/arm/lib/lib.a $(LIBS)

5) 编译信息:CPP, CC, AS, LD, AR,CFLAGS,LINKFLAGS
在 Rules.make 中定义的是编译的通用规则,具体到特定的场合,需要明确给出编译环境,编译环境就是在以上的变量中定义的。针对交叉编译的要求,定义了 CROSS_COMPILE。比如:

CROSS_COMPILE   = arm-linux-
CC              = $(CROSS_COMPILE)gcc
LD              = $(CROSS_COMPILE)ld

CROSS_COMPILE 定义了交叉编译器前缀 arm-linux-,表明所有的交叉编译工具都是以 arm-linux- 开头的,所以在各个交叉编译器工具之前,都加入了 $(CROSS_COMPILE),以组成一个完整的交叉编译工具文件名,比如 arm-linux-gcc。
CFLAGS 定义了传递给 C 编译器的参数。
LINKFLAGS 是链接生成 vmlinux 时,由链接器使用的参数。LINKFLAGS 在 arm/*/Makefile 中定义,比如:

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

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 结尾。

威客
威客

PHP威客系统威客贰系统是国内领先的威客网站内容管理系统,基于PHP+Mysql架构开发。整合UCHOME系统,系统内容模块由:威客悬赏,招标任务,人才库,人才,招聘,新闻资讯,在线支付,发贴推广,案例示范等多种功能组成。 威客贰系统独创的单人悬赏、 多人悬赏 、计件悬赏 、 定金招标、 本地招标为核心任务模式。超强的发贴推广可以分配到不同的任务模式不同的会员等级有不同的提成费用,根据网站自身需要

下载

子目录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-(CONFIGTC)+=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

配置文件

配置文件功能概述

除了 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

实例

对于一个开发者来说,将自己开发的内核代码加入到 Linux 内核中,需要有三个步骤。首先确定把自己开发代码放入到内核的位置;其次,把自己开发的功能增加到 Linux 内核的配置选项中,使用户能够选择此功能;最后,构建子目录 Makefile,根据用户的选择,将相应的代码编译到最终生成的 Linux 内核中去。下面,我们就通过一个简单的例子–test driver,结合前面学到的知识,来说明如何向 Linux 内核中增加新的功能。

目录结构

test driver 放置在 drivers/test/ 目录下:

cddrivers/testtree

.
|– Config.in
|– Makefile
|– cpu
| |– Makefile
| -- cpu.c
|-- test.c
|-- test_client.c
|-- test_ioctl.c
|-- test_proc.c
|-- test_queue.c
– test
|– Makefile

配置文件

# TEST driver configuration
#
mainmenu_option next_comment
comment 'TEST Driver'
bool 'TEST support' CONFIG_TEST
if [ "$CONFIG_TEST" = "y" ]; then
  tristate 'TEST user-space interface' CONFIG_TEST_USER
  bool 'TEST CPU ' CONFIG_TEST_CPU
fi
endmenu

由于 test driver 对于内核来说是新的功能,所以首先创建一个菜单 TEST Driver。然后,显示 “TEST support”,等待用户选择;接下来判断用户是否选择了 TEST Driver,如果是(CONFIG_TEST=y),则进一步显示子功能:用户接口与 CPU 功能支持;由于用户接口功能可以被编译成内核模块,所以这里的询问语句使用了 tristate(因为 tristate 的取值范围包括 y、n 和 m,m 就是对应着模块)。
2) arch/arm/config.in
在文件的最后加入:source drivers/test/Config.in,将 TEST Driver 子功能的配置纳入到 Linux 内核的配置中。

Makefile

1)drivers/test/Makefile

#       drivers/test/Makefile
#
#       Makefile for the TEST.
#
SUB_DIRS     :=
MOD_SUB_DIRS := $(SUB_DIRS)
ALL_SUB_DIRS := $(SUB_DIRS) cpu
L_TARGET := test.a
export-objs := test.o test_client.o
obj-$(CONFIG_TEST)              += test.o test_queue.o test_client.o
obj-$(CONFIG_TEST_USER)         += test_ioctl.o
obj-$(CONFIG_PROC_FS)           += test_proc.o
subdir-$(CONFIG_TEST_CPU)       += cpu
include $(TOPDIR)/Rules.make
clean:
        for dir in $(ALL_SUB_DIRS); do make -C $$dir clean; done
        rm -f *.[oa] .*.flags

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 列表中。 

2)drivers/test/cpu/Makefile

#       drivers/test/test/Makefile
#
#       Makefile for the TEST CPU 
#
SUB_DIRS     :=
MOD_SUB_DIRS := $(SUB_DIRS)
ALL_SUB_DIRS := $(SUB_DIRS)
L_TARGET := test_cpu.a
obj-$(CONFIG_test_CPU)       += cpu.o
include $(TOPDIR)/Rules.make
clean:
        rm -f *.[oa] .*.flags

3)drivers/Makefile

……
subdir-$(CONFIG_TEST)      += test
……
include $(TOPDIR)/Rules.make

在 drivers/Makefile 中加入 subdir-$(CONFIG_TEST)+= test,使得在用户选择 TEST Driver 功能后,内核编译时能够进入 test 目录。 

4)Makefile

……
DRIVERS-$(CONFIG_PLD) += drivers/pld/pld.o
DRIVERS-$(CONFIG_TEST) += drivers/test/test.a
DRIVERS-$(CONFIG_TEST_CPU) += drivers/test/cpu/test_cpu.a
DRIVERS := $(DRIVERS-y)
……

在顶层 Makefile 中加入 DRIVERS-(CONFIGTEST)+=drivers/test/test.a和DRIVERS−(CONFIGTEST)+=drivers/test/test.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视频教程

相关专题

更多
Golang gRPC 服务开发与Protobuf实战
Golang gRPC 服务开发与Protobuf实战

本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。

8

2026.01.15

公务员递补名单公布时间 公务员递补要求
公务员递补名单公布时间 公务员递补要求

公务员递补名单公布时间不固定,通常在面试前,由招录单位(如国家知识产权局、海关等)发布,依据是原入围考生放弃资格,会按笔试成绩从高到低递补,递补考生需按公告要求限时确认并提交材料,及时参加面试/体检等后续环节。要求核心是按招录单位公告及时响应、提交材料(确认书、资格复审材料)并准时参加面试。

44

2026.01.15

公务员调剂条件 2026调剂公告时间
公务员调剂条件 2026调剂公告时间

(一)符合拟调剂职位所要求的资格条件。 (二)公共科目笔试成绩同时达到拟调剂职位和原报考职位的合格分数线,且考试类别相同。 拟调剂职位设置了专业科目笔试条件的,专业科目笔试成绩还须同时达到合格分数线,且考试类别相同。 (三)未进入原报考职位面试人员名单。

58

2026.01.15

国考成绩查询入口 国考分数公布时间2026
国考成绩查询入口 国考分数公布时间2026

笔试成绩查询入口已开通,考生可登录国家公务员局中央机关及其直属机构2026年度考试录用公务员专题网站http://bm.scs.gov.cn/pp/gkweb/core/web/ui/business/examResult/written_result.html,查询笔试成绩和合格分数线,点击“笔试成绩查询”按钮,凭借身份证及准考证进行查询。

11

2026.01.15

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

65

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

36

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

75

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

21

2026.01.13

PHP 文件上传
PHP 文件上传

本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

35

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.2万人学习

Git 教程
Git 教程

共21课时 | 2.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号