linux 内核配置机制(make menuconfig、Kconfig、makefile)讲解

本文详细介绍了Linux内核的编译过程,包括如何通过makemenuconfig进行配置,Kconfig文件的作用,以及如何将模块编译进内核或生成模块文件。通过具体实例展示了整个流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前面我们介绍模块编程的时候介绍了驱动进入内核有两种方式:模块和直接编译进内核,并介绍了模块的一种编译方式——在一个独立的文件夹通过makefile配合内核源码路径完成

    那么如何将驱动直接编译进内核呢?

    在我们实际内核的移植配置过程中经常听说的内核裁剪又是怎么麽回事呢?

我们在进行linux内核配置的时候经常会执行make menuconfig这个命令,然后屏幕上会出现以下界面:



这个界面是怎么生成的呢?

跟我们经常说的内核配置与与编译又有什么关系呢?

下面我们借此来讲解一下linux内核的配置机制及其编译过程。

一、配置系统的基本结构

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

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

    2、配置文件(config.in(2.4内核,2.6内核)):给用户提供配置选择的功能;

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

   这些配置工具都是使用脚本语言,如 Tcl/TK、Perl 编写的(也包含一些用 C 编写的代码)。本文并不是对配置系统本身进行分析,而是介绍如何使用配置系统。所以,除非是配置系统的维护者,一般的内核开发者无须了解它们的原理,只需要知道如何编写 Makefile 和配置文件就可以。

二、makefile menuconfig过程讲解

当我们在执行make menuconfig这个命令时,系统到底帮我们做了哪些工作呢?

这里面一共涉及到了一下几个文件我们来一一讲解

Linux内核根目录下的scripts文件夹

arch/$ARCH/Kconfig文件、各层目录下的Kconfig文件

Linux内核根目录下的makefile文件、各层目录下的makefile文件

Linux内核根目录下的的.config文件、arm/$ARCH/下的config文件

Linux内核根目录下的 include/generated/autoconf.h文件

1)scripts文件夹存放的是跟make menuconfig配置界面的图形绘制相关的文件,我们作为使用者无需关心这个文件夹的内容


2)当我们执行make menuconfig命令出现上述蓝色配置界面以前,系统帮我们做了以下工作:

    首先系统会读取arch/$ARCH/目录下的Kconfig文件生成整个配置界面选项(Kconfig是整个linux配置机制的核心),那么ARCH环境变量的值等于多少呢?

它是由linux内核根目录下的makefile文件决定的,在makefile下有此环境变量的定义:


或者通过 make ARCH=arm menuconfig命令来生成配置界面,默认生成的界面是所有参数都是没有值的

    比如教务处进行考试,考试科数可能有外语、语文、数学等科,这里相当于我们选择了arm科可进行考试,系统就会读取arm/arm/kconfig文件生成配置选项(选择了arm科的卷子),系统还提供了x86科、milps科等10几门功课的考试题


3)假设教务处比较“仁慈”,为了怕某些同学做不错试题,还给我们准备了一份参考答案(默认配置选项),存放在arch/$ARCH/configs下,对于arm科来说就是arch/arm/configs文件夹:


    此文件夹中有许多选项,系统会读取哪个呢?内核默认会读取linux内核根目录下.config文件作为内核的默认选项(试题的参考答案),我们一般会根据开发板的类型从中选取一个与我们开发板最接近的系列到Linux内核根目录下(选择一个最接近的参考答案)

#cp arch/arm/configs/s3c2410_defconfig .config

4).config

    假设教务处留了一个心眼,他提供的参考答案并不完全正确(.config文件与我们的板子并不是完全匹配),这时我们可以选择直接修改.config文件然后执行make menuconfig命令读取新的选项

    但是一般我们不采取这个方案,我们选择在配置界面中通过空格、esc、回车选择某些选项选中或者不选中,最后保存退出的时候,Linux内核会把新的选项(正确的参考答案)更新到.config中,此时我们可以把.config重命名为其它文件保存起来(当你执行make distclean时系统会把.config文件删除),以后我们再配置内核时就不需要再去arch/arm/configs下考取相应的文件了,省去了重新配置的麻烦,直接将保存的.config文件复制为.config即可.

5)经过以上两步,我们可以正确的读取、配置我们需要的界面了

那么他们如何跟makefile文件建立编译关系呢?

当你保存make menuconfig选项时,系统会除了会自动更新.config外,还会将所有的选项以宏的形式保存在

Linux内核根目录下的 include/generated/autoconf.h文件下


内核中的源代码就都会包含以上.h文件,跟宏的定义情况进行条件编译。

当我们需要对一个文件整体选择如是否编译时,还需要修改对应的makefile文件,例如:


    我们选择是否要编译s3c2410_ts.c这个文件时,makefile会根据CONFIG_TOUCHSCREEN_S3C2410来决定是编译此文件,此宏是在Kconfig文件中定义,当我们配置完成后,会出现在.config及autconf中,至此,我们就完成了整个linux内核的编译过程。

    最后我们会发现,整个linux内核配置过程中,留给用户的接口其实只有各层Kconfig、makefile文件以及对应的源文件。

    比如我们如果想要给内核增加一个功能,并且通过make menuconfig控制其声称过程

    首先需要做的工作是:修改对应目录下的Kconfig文件,按照Kconfig语法增加对应的选项;

    其次执行make menuconfig选择编译进内核或者不编译进内核,或者编译为模块,.config文件和autoconf.h文件会自动生成;

    最后修改对应目录下的makefile文件完成编译选项的添加;

    最后的最后执行make zImage命令进行编译。

三、具体实例

下面我们以前面做过的模块实验为例,讲解如何通过make menuconfig机制将前面单独编译的模块编译进内核或编译为模块

假设我已经有了这么一个驱动:

modules.c

#include <linux/module.h>       /*module_init()*/
#include <linux/kernel.h>	/* printk() */
#include <linux/init.h>		/* __init __exit */

#define DEBUG	//open debug message

#ifdef DEBUG
#define PRINTK(fmt, arg...)		printk(KERN_WARNING fmt, ##arg)
#else
#define PRINTK(fmt, arg...)		printk(KERN_DEBUG fmt, ##arg)
#endif

/* Module Init & Exit function */
static int __init myModule_init(void)
{
	/* Module init code */
	PRINTK("myModule_init\n");
	return 0;
}

static void __exit myModule_exit(void)
{
	/* Module exit code */
	PRINTK("myModule_exit\n");
	return;
}

module_init(myModule_init);
module_exit(myModule_exit);

MODULE_AUTHOR("dengwei");                          /*模块作者,可选*/
MODULE_LICENSE("GPL");                             /*模块许可证明,描述内核模块的许可权限,必须*/
MODULE_DESCRIPTION("A simple Hello World Module"); /*模块说明,可选*/

Step1:将modules.c拷到drivers/char/目录下(这个文件夹一般存放常见的字符驱动)

Step2: vi driver/char/Kconfig,在
    config DEVKMEM后添加以下信息

config MODULES
tristate "modules device support"
default y
help
 Say Y here,the modules will be build in kernel.
 Say M here,the modules willbe build to modules.
 Say N here,there will be nothing to be do. 

Step3:make menuconfig
     Device driver-character devices
           [*]modules device suppor

Step4:vi driver/char/Makefile,在js-rtc后添加
obj-$(CONFIG_MODULES)+= modules.o
CONFIG_MODULES 必须跟上面的Kconfig中保持一致,系统会自动添加CONFIG_前缀

modules.o必须跟你加入的.c文件名一致

最后执行:make zImage modules就会被编译进内核中


第三步:

Step3:make menuconfig
     Device driver-character devices
           [M]modules device suppor
把星号在配置界面通过空格改为M,最后执行make modules,在driver/char/目录下会生成一个modules.ko文件

跟我们前面讲的单独编译模块效果一样,也会生成一个模块,将它考入开发板执行insmod moudles.ko,即可将生成的模块插入内核使用

<think>我们正在讨论的是通过`make menuconfig`命令来配置Linux内核,以实现精简编译。 问题:使用`make menuconfig`命令之后的页面可以精简内核编译吗? 回答:是的,使用`make menuconfig`命令后出现的配置界面可以用于精简内核编译。通过这个界面,用户可以选择性地禁用不需要的内核模块和功能,从而减少内核的大小。 解释: `make menuconfig`是一个基于ncurses的文本界面配置工具,它允许用户通过菜单交互的方式配置Linux内核的编译选项。在这个界面中,每个配置选项通常有三种状态: - [*] 编译进内核(表示该功能将直接构建在内核镜像中) - [M] 编译为模块(表示该功能将编译为可加载的内核模块,可以在需要时动态加载) - [ ] 不编译(表示完全排除该功能) 精简内核的步骤通常包括: 1. 移除不需要的硬件驱动(如老式设备的驱动、不使用的接口驱动等)。 2. 禁用不需要的内核特性(如文件系统支持、网络协议、调试功能等)。 3. 将一些功能编译为模块,而不是直接编译进内核,这样只有需要时才会加载,减小初始内核镜像的大小。 在配置界面中,可以通过方向键导航,Enter键进入子菜单,空格键切换选项的状态。在配置时,我们可以根据系统的实际需求,关闭不需要的功能。 例如,如果我们的系统不需要声音设备,可以在配置界面中找到“Sound card support”并禁用它。同样,如果系统不需要网络功能,可以禁用整个网络子系统。 注意:精简内核需要谨慎,因为禁用必要的功能可能导致系统无法启动或某些硬件无法使用。通常建议保留当前内核配置作为基础(通过复制现有系统的`/boot/config-$(uname -r)`文件到内核源码目录下的`.config`),然后在这个基础上进行修改。 下面是一个示例,展示如何通过C代码来检查内核配置(在用户空间程序中): 我们可以读取`/proc/config.gz`(如果启用了`IKCONFIG_PROC`)来获取当前内核配置,然后对比我们精简的配置。 但是请注意,由于问题要求只能提供C语言代码,这里提供一个简单的C程序来检查内核是否支持某个特性(通过检查`/boot/config-*`文件):</think>### 通过 `make menuconfig` 精简内核编译详解 #### 1. `make menuconfig` 的核心作用 **是的,通过 `make menuconfig` 配置界面可以精确精简内核编译**。这是 Linux 内核配置的主要交互式工具,基于 C 语言实现的 Kconfig 系统构建。 #### 2. 精简内核的关键配置项(C语言开发者视角) ##### 处理器架构优化 ```c // 在 .config 中的配置示例 CONFIG_64BIT=y // 仅64位支持 CONFIG_M486=n // 禁用486兼容 CONFIG_X86_USE_PPRO_CHECK=n // 禁用过时CPU检查 ``` ##### 驱动精简(典型配置) ```c // 禁用不需要的设备驱动 CONFIG_SOUND=n // 声音驱动 CONFIG_USB_SUPPORT=n // USB支持 CONFIG_INPUT_MOUSE=n // 鼠标支持 CONFIG_DRM_AMDGPU=n // AMD显卡驱动 ``` ##### 文件系统精简 ```c CONFIG_EXT4_FS=y // 仅保留EXT4 CONFIG_BTRFS_FS=n CONFIG_XFS_FS=n CONFIG_FAT_FS=n ``` ##### 网络协议栈精简 ```c CONFIG_NET=y // 保留基础网络 CONFIG_INET=y CONFIG_IPV6=n // 禁用IPv6 CONFIG_WIRELESS=n // 禁用无线 ``` #### 3. 配置界面操作指南 ```mermaid graph TB A[主菜单] --> B[Processor type and features] A --> C[Device Drivers] A --> D[File systems] A --> E[Networking support] B --> B1[CPU优化选项] C --> C1[存储驱动] C --> C2[网络驱动] D --> D1[文件系统] E --> E1[网络协议] ``` 操作步骤: 1. 使用方向键导航 2. 空格键切换状态: - `[*]` 编译进内核 - `[M]` 编译为模块 - `[ ]` 完全禁用 3. `/` 键搜索配置项 4. `Esc` 返回上级菜单 #### 4. 内核精简的 C 语言实现原理 Kconfig 系统的工作流程: ```c // 简化版 Kconfig 解析器逻辑 void parse_kconfig(void) { while(token = get_next_token()) { switch(token.type) { case CONFIG_OPTION: handle_config_option(token); break; case MENU_ENTRY: create_menu_entry(token); break; case DEPENDS_ON: handle_dependency(token); break; } } } ``` #### 5. 配置后的编译验证代码 ```c #include <stdio.h> #include <linux/version.h> int main() { // 检查内核版本 printf("Compiled kernel version: %s\n", UTS_RELEASE); // 验证配置选项 #ifdef CONFIG_SMP printf("SMP support: ENABLED\n"); #else printf("SMP support: DISABLED\n"); #endif #ifdef CONFIG_IPV6 printf("IPv6 support: ENABLED\n"); #else printf("IPv6 support: DISABLED\n"); #endif return 0; } ``` #### 6. 常见精简错误及解决方法 **错误1:过度精简导致启动失败** ```bash Kernel panic - not syncing: VFS: Unable to mount root fs ``` **解决**:确保保留必要的文件系统驱动和存储驱动 **错误2:模块依赖缺失** ```bash modprobe: FATAL: Module ext4 not found ``` **解决**:检查 `CONFIG_EXT4_FS` 是否设置为 `y` 或 `m` **错误3:硬件不识别** ```bash usb 1-1: device not accepting address ``` **解决**:启用必要的基础硬件支持(如 `CONFIG_USB_SUPPORT`) #### 7. 自动化精简配置脚本示例 ```bash #!/bin/bash # 精简内核配置脚本 cp /boot/config-$(uname -r) .config # 禁用不需要的驱动 scripts/config --disable SOUND scripts/config --disable USB_SUPPORT scripts/config --disable INPUT_MOUSE # 启用基础功能 scripts/config --enable EXT4_FS scripts/config --enable TTY scripts/config --enable SERIAL_8250 # 更新配置 make olddefconfig ``` ### 内核精简前后对比指标 | 配置项 | 完整内核 | 精简内核 | 优化效果 | |--------|----------|----------|----------| | 内核大小 | 15-20MB | 3-5MB | 减少60-75% | | 编译时间 | 30-60分钟 | 10-20分钟 | 减少50-70% | | 内存占用 | 50-100MB | 20-40MB | 减少50-60% | | 系统调用 | 400+ | 150-200 | 减少50-60% | | 驱动模块 | 3000+ | 500-800 | 减少70-85% | ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值