Heim  >  Artikel  >  Betrieb und Instandhaltung  >  Das Linux-Kernel-Konfigurationssystem besteht aus mehreren Teilen

Das Linux-Kernel-Konfigurationssystem besteht aus mehreren Teilen

青灯夜游
青灯夜游Original
2023-03-16 09:39:062564Durchsuche

Das Linux-Kernel-Konfigurationssystem besteht aus 3 Teilen: 1. Makefile, das im Linux-Kernel-Quellcode-Stammverzeichnis und jedem Layer-Verzeichnis verteilt ist und die Kompilierungsregeln des Linux-Kernels definiert 2. Konfigurationsdatei (config.in) , das Benutzern die Möglichkeit bietet, die Auswahl zu konfigurieren; 3. Konfigurationstools, einschließlich Konfigurationsbefehlsinterpreter (der in Konfigurationsskripten verwendete Konfigurationsbefehle interpretiert) und Konfigurationsbenutzeroberfläche.

Das Linux-Kernel-Konfigurationssystem besteht aus mehreren Teilen

Die Betriebsumgebung dieses Tutorials: Linux7.3-System, Dell G3-Computer.

Das Linux-Kernel-Konfigurationssystem besteht aus drei Teilen: Makefile, Konfigurationsdatei (config.in) und Konfigurationstools.

  • Makefile: Wird im Stammverzeichnis des Linux-Kernels und in jedem Layer-Verzeichnis verteilt und definiert die Kompilierungsregeln des Linux-Kernels.

  • Konfigurationsdatei (config.in): Bietet Benutzern die Möglichkeit, Konfigurationen vorzunehmen Auswahlmöglichkeiten;

  • Konfigurationstools: einschließlich Konfigurationsbefehlsinterpreter (interpretiert die im Konfigurationsskript verwendeten Konfigurationsbefehle) und Konfigurationsbenutzeroberfläche (bereitstellung einer zeichenbasierten Benutzeroberfläche, einer Ncurses-basierten grafischen Benutzeroberfläche und einer Xwindows-basierten Benutzerkonfigurationsoberfläche), jeweils entsprechend Make config, Make menuconfig und make xconfig).

Diese Konfigurationstools werden mit Skriptsprachen wie Tcl/TK und Perl geschrieben (enthalten auch einige in C geschriebene Codes). Bei diesem Artikel handelt es sich nicht um eine Analyse des Konfigurationssystems selbst, sondern um eine Einführung in die Verwendung des Konfigurationssystems. Daher müssen normale Kernel-Entwickler deren Prinzipien nicht verstehen, es sei denn, sie sind Betreuer von Konfigurationssystemen. Sie müssen lediglich wissen, wie man Makefiles und Konfigurationsdateien schreibt. Daher besprechen wir in diesem Artikel nur Makefiles und Konfigurationsdateien. Wenn es um Inhalte zu bestimmten CPU-Architekturen geht, verwenden wir außerdem ARM als Beispiel. Dies verdeutlicht nicht nur die besprochenen Probleme, sondern hat auch keine Auswirkungen auf den Inhalt selbst.

Makefile

Übersicht über Makefile

Die Funktion von Makefile besteht darin, eine Liste von Quelldateien zu erstellen, die basierend auf der Konfiguration kompiliert werden müssen, sie dann separat zu kompilieren und die Zielcodes miteinander zu verknüpfen Erstellen Sie schließlich ein Linux-Kernel-Binärdokument.

Da der Linux-Kernel-Quellcode nach einer Baumstruktur organisiert ist, werden auch Makefiles im Verzeichnisbaum verteilt. Makefiles im Linux-Kernel und Dateien, die direkt mit Makefiles in Zusammenhang stehen, sind:

  • Makefile: Das Makefile der obersten Ebene ist die Gesamtsteuerdatei für die gesamte Kernelkonfiguration und -kompilierung.

  • .config: Kernel-Konfigurationsdatei, die vom Benutzer ausgewählte Konfigurationsoptionen enthält und zum Speichern der Ergebnisse der Kernel-Konfiguration (z. B. make config) verwendet wird.

  • arch/*/Makefile: Makefiles, die sich in verschiedenen CPU-Systemverzeichnissen befinden, wie etwa arch/arm/Makefile, sind Makefiles für bestimmte Plattformen.

  • Makefile in jedem Unterverzeichnis: z. B. drivers/Makefile, ist für die Verwaltung des Quellcodes im Unterverzeichnis verantwortlich.

  • Rules.make: Regeldatei, die von allen Makefiles verwendet wird.

Nachdem der Benutzer die Konfiguration über make config vorgenommen hat, wird .config generiert. Das Makefile der obersten Ebene liest die Konfigurationsoptionen in .config. Das Makefile der obersten Ebene hat zwei Hauptaufgaben: das Generieren von VMlinux-Dateien und Kernelmodulen. Um dieses Ziel zu erreichen, betritt das Makefile der obersten Ebene rekursiv jedes Unterverzeichnis des Kernels und ruft die Makefiles auf, die sich jeweils in diesen Unterverzeichnissen befinden. Welche Unterverzeichnisse eingegeben werden müssen, hängt von der Kernel-Konfiguration ab. Im Makefile der obersten Ebene gibt es einen Satz: include arch/$(ARCH)/Makefile, der das Makefile unter einer bestimmten CPU-Architektur enthält. Dieses Makefile enthält plattformbezogene Informationen.

Das Makefile in jedem Unterverzeichnis erstellt außerdem eine Liste der Quelldateien, die für die aktuelle Konfiguration erforderlich sind, basierend auf den von .config bereitgestellten Konfigurationsinformationen, und schließt am Ende der Datei den Wert include $(TOPDIR)/Rules.make ein.

Die Datei Rules.make spielt eine sehr wichtige Rolle, sie definiert Kompilierungsregeln, die allen Makefiles gemeinsam sind. Wenn Sie beispielsweise alle C-Programme in diesem Verzeichnis in Assemblercode kompilieren müssen, müssen im Makefile die folgenden Kompilierungsregeln vorhanden sein:

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

Es gibt viele Unterverzeichnisse, die die gleichen Anforderungen haben, also müssen Sie sie hinzufügen sie in jedem Das Makefile enthält diese Kompilierungsregel, die problematischer sein wird. Im Linux-Kernel werden solche Kompilierungsregeln einheitlich in Rules.make platziert und in Rules.make (einschließlich Rules.make) in ihren jeweiligen Makefiles enthalten, wodurch eine Duplizierung derselben Regeln in mehreren Makefile-Regeln vermieden wird. Für das obige Beispiel lauten die entsprechenden Regeln in Rules.make:

%.s: %.c
    (CC)  (CFLAGS)     (EXTRACFLAGS)  (CFLAGS_     (F))  (CFLAGS_     @)S  < -o $@

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

子目录Makefile

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

# Makefile for the linux kernel.
#
# All of the (potential) objects that export symbols.
# This list comes from &#39;grep -l EXPORT_SYMBOL *.[hc]&#39;.
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 <br> |-- test.c <br> |-- test_client.c <br> |-- test_ioctl.c <br> |-- test_proc.c <br> |-- test_queue.c <br>– test
|– Makefile

配置文件

# TEST driver configuration
#
mainmenu_option next_comment
comment &#39;TEST Driver&#39;
bool &#39;TEST support&#39; CONFIG_TEST
if [ "$CONFIG_TEST" = "y" ]; then
  tristate &#39;TEST user-space interface&#39; CONFIG_TEST_USER
  bool &#39;TEST CPU &#39; 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视频教程

Das obige ist der detaillierte Inhalt vonDas Linux-Kernel-Konfigurationssystem besteht aus mehreren Teilen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Vorheriger Artikel:Was bedeutet Linux RC?Nächster Artikel:Was bedeutet Linux RC?