百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 优雅编程 > 正文

Linux内核kernel配置1—你真懂makefile、menuconfig、xconfig吗

sinye56 2025-02-21 15:17 5 浏览 0 评论

随着 Linux 操作系统的广泛应用,特别是 Linux 在嵌入式领域的发展,越来越多的人开始投身到 Linux 内核级的开发中。

面对日益庞大的Linux 内核源代码,开发者在完成自己的内核代码后,都将面临着同样的问题,即如何将源代码融入到 Linux 内核中,增加相应的 Linux 配置选 项,并最终被编译进 Linux 内核。这就需要了解 Linux 的内核配置系统。

众所周知,Linux 内核是由分布在全球的 Linux 爱好者共同开发的,Linux 内核每天都面临着许多新的变化。但是,Linux 内核的组织并没有 出现混乱的现象,反而显得非常的简洁,而且具有很好的扩展性,开发人员可以很方便的向 Linux内核中增加新的内容。原因之一就是 Linux 采用了模块化的内核配置系统,从而保证了内核的扩展性。

本文首先分析了 Linux 内核中的配置系统结构,然后,解释了 Makefile 和配置文件的格式以及配置语句的含义,最后,通过一个简单的例子--TEST Driver,具体说明如何将自行开发的代码加入到Linux 内核中。


说明:

本人近期会陆续上传这些资料和视频教程,可以关注一下互相交流:C C++ Java python linux ARM 嵌入式 物联网等。

哪位朋友需要完整电子档的在评论区给我说下,本人有时间了一一私发给大家哈O(∩_∩)O


1. 配置系统的基本结构

Linux内核的配置系统由三个部分组成,分别是:

1. Makefile:分布在 Linux 内核源代码中的 Makefile,定义 Linux 内核的编译规则;

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

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

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

内容:

配置系统的基本结构

Makefile

配置文件

实例参考资料 关于作者

在 Linux 专区还有:

教程

工具与产品 代码与组件

文章



2.1 Makefile 概述

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

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

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

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

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

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

5. 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) $(EXTRA_CFLAGS) $(CFLAGS_$(*F)) $(CFLAGS_$@) -S $< -o $@



2.2 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

6) 配置变量CONFIG_*

.config 文件中有许多的配置变量等式,用来说明用户配置的结果。例如 CONFIG_MODULES=y 表明用户选择了 Linux 内核的模块功能。

.config 被顶层 Makefile 包含后,就形成许多的配置变量,每个配置变量具有确定的值:y 表示本编译选项对应的内核代码被静态编译进 Linux 内核;m 表示本编译选项对应的内核代码被编译成模

块;n 表示不选择此编译选项;如果根本就没有选择,那么配置变量的值为空。



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

2.4 子目录 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-$(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 $(filter-out $(export-objs), $(obj-y))) 定义了 L_OBJS 的生成方式:在 obj-y 的列

表中过滤掉 export-objs(tc.o),然后排序并去除重复的文件名。这里使用到了 GNU Make 的一些特殊功能,具体的含义可参考 Make 的文档(info make)。

d) include $(TOPDIR)/Rules.make

相关推荐

程序员:JDK的安装与配置(完整版)_jdk的安装方法

对于Java程序员来说,jdk是必不陌生的一个词。但怎么安装配置jdk,对新手来说确实头疼的一件事情。我这里以jdk10为例,详细的说明讲解了jdk的安装和配置,如果有不明白的小伙伴可以评论区留言哦下...

Linux中安装jdk并配置环境变量_linux jdk安装教程及环境变量配置

一、通过连接工具登录到Linux(我这里使用的Centos7.6版本)服务器连接工具有很多我就不一一介绍了今天使用比较常用的XShell工具登录成功如下:二、上传jdk安装包到Linux服务器jdk...

麒麟系统安装JAVA JDK教程_麒麟系统配置jdk

检查检查系统是否自带java在麒麟系统桌面空白处,右键“在终端打开”,打开shell对话框输入:java–version查看是否自带java及版本如图所示,系统自带OpenJDK,要先卸载自带JDK...

学习笔记-Linux JDK - 安装&amp;配置

前提条件#检查是否存在JDKrpm-qa|grepjava#删除现存JDKyum-yremovejava*安装OracleJDK不分系统#进入安装文件目...

Linux新手入门系列:Linux下jdk安装配置

本系列文章是把作者刚接触和学习Linux时候的实操记录分享出来,内容主要包括Linux入门的一些理论概念知识、Web程序、mysql数据库的简单安装部署,希望能够帮到一些初学者,少走一些弯路。注意:L...

测试员必备:Linux下安装JDK 1.8你必须知道的那些事

1.简介在Oracle收购Sun后,Java的一系列产品就被整合到Oracle官网中,打开官网乍眼一看也不知道去哪里下载,还得一个一个的摸索尝试,而且网上大多数都是一些Oracle收购Sun前,或者就...

Linux 下安装JDK17_linux 安装jdk1.8 yum

一、安装环境操作系统:JDK版本:17二、安装步骤第一步:下载安装包下载Linux环境下的jdk1.8,请去官网(https://www.oracle.com/java/technologies/do...

在Ubuntu系统中安装JDK 17并配置环境变量教程

在Ubuntu系统上安装JDK17并配置环境变量是Java开发环境搭建的重要步骤。JDK17是Oracle提供的长期支持版本,广泛用于开发Java应用程序。以下是详细的步骤,帮助你在Ubuntu系...

如何在 Linux 上安装 Java_linux安装java的步骤

在桌面上拥抱Java应用程序,然后在所有桌面上运行它们。--SethKenlon(作者)无论你运行的是哪种操作系统,通常都有几种安装应用程序的方法。有时你可能会在应用程序商店中找到一个应用程序...

Windows和Linux环境下的JDK安装教程

JavaDevelopmentKit(简称JDK),是Java开发的核心工具包,提供了Java应用程序的编译、运行和开发所需的各类工具和类库。它包括了JRE(JavaRuntimeEnviro...

linux安装jdk_linux安装jdk软连接

JDK是啥就不用多介绍了哈,外行的人也不会进来看我的博文。依然记得读大学那会,第一次实验课就是在机房安装jdk,编写HelloWorld程序。时光飞逝啊,一下过了十多年了,挣了不少钱,买了跑车,娶了富...

linux安装jdk,全局配置,不同用户不同jdk

jdk1.8安装包链接:https://pan.baidu.com/s/14qBrh6ZpLK04QS8ogCepwg提取码:09zs上传文件解压tar-zxvfjdk-8u152-linux-...

运维大神教你在linux下安装jdk8_linux安装jdk1.7

1.到官网下载适合自己机器的版本。楼主下载的是jdk-8u66-linux-i586.tar.gzhttp://www.oracle.com/technetwork/java/javase/downl...

window和linux安装JDK1.8_linux 安装jdk1.8.tar

Windows安装JDK1.8的步骤:步骤1:下载JDK打开浏览器,找到JDK下载页面https://d.injdk.cn/download/oraclejdk/8在页面中找到并点击“下载...

最全的linux下安装JavaJDK的教程(图文详解)不会安装你来打我?

默认已经有了linux服务器,且有root账号首先检查一下是否已经安装过java的jdk任意位置输入命令:whichjava像我这个已经安装过了,就会提示在哪个位置,你的肯定是找不到。一般我们在...

取消回复欢迎 发表评论: