news 2026/4/28 1:58:10

【内核驱动基础】内核模块的两种编译方式(in-tree vs out-of-tree)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【内核驱动基础】内核模块的两种编译方式(in-tree vs out-of-tree)

目录

一、内核模块的编译方式(in-tree vs out-of-tree)

二、内核树外编译(out-of-tree)

特点

典型做法

适用场景

三、内核树内编译(in-tree)

参考资料


一、内核模块的编译方式(in-tree vs out-of-tree)

通常而言,内核模块代码有两种常见的构建形态:

  1. 内核树内编译(in-tree):把模块源码放进(或集成进)内核源码树,由内核顶层构建系统统一编译。
  2. 内核树外编译(out-of-tree,外部模块):模块源码独立放在内核树之外,通过make -C <kernel_dir> M=<module_dir> modules借用内核 Kbuild 来编译。

二、内核树外编译(out-of-tree)

特点

  • 模块源码独立,不需要进入内核源码树。

  • 仍然使用内核的 Kbuild 规则来编译,关键命令是:

    make -C <KERNEL_DIR> M=<MODULE_DIR> modules

典型做法

  • 模块目录里只放一个“外部模块 Makefile”
    • obj-m := hellomodule.o
    • make -C $(KERNEL_DIR) M=$(CURDIR) modules

适用场景

  • 驱动/模块开发调试(迭代快)
  • 第三方闭源或单独交付(不改内核树)
  • 同一内核版本下给多个项目复用

在内核树外编译的方式在我们之前的文章中其实已经实现了,可以参考【内核驱动基础】超详细一文详解Linux驱动模块这一文章,主要实现就是Makefile文件的编写

三、内核树内编译(in-tree)

在内核源码的文件目录下,我们可以看到有很多的驱动程序,我们通过drivers/char中的Makefile文件进一步举例说明,其位置如下:

Makefile文件的内容如下:

# SPDX-License-Identifier: GPL-2.0 # # Makefile for the kernel character device drivers. # obj-y += mem.o random.o obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o obj-y += misc.o obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_MSPEC) += mspec.o obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o obj-$(CONFIG_IBM_BSR) += bsr.o obj-$(CONFIG_PRINTER) += lp.o obj-$(CONFIG_APM_EMULATION) += apm-emulation.o obj-$(CONFIG_DTLK) += dtlk.o obj-$(CONFIG_APPLICOM) += applicom.o obj-$(CONFIG_SONYPI) += sonypi.o obj-$(CONFIG_HPET) += hpet.o obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap/ obj-$(CONFIG_NVRAM) += nvram.o obj-$(CONFIG_TOSHIBA) += toshiba.o obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_HW_RANDOM) += hw_random/ obj-$(CONFIG_PPDEV) += ppdev.o obj-$(CONFIG_NWBUTTON) += nwbutton.o obj-$(CONFIG_NWFLASH) += nwflash.o obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o obj-$(CONFIG_GPIO_TB0219) += tb0219.o obj-$(CONFIG_TELCLOCK) += tlclk.o obj-$(CONFIG_MWAVE) += mwave/ obj-y += agp/ obj-$(CONFIG_PCMCIA) += pcmcia/ obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o obj-$(CONFIG_TCG_TPM) += tpm/ obj-$(CONFIG_PS3_FLASH) += ps3flash.o obj-$(CONFIG_XILLYBUS) += xillybus/ obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o obj-$(CONFIG_ADI) += adi.o

这个文件的主要作用就是告诉内核的构建系统(Kbuild)在“字符设备驱动”这个目录下,需要编译哪些源文件/子目录,以及它们是编进内核(built-in)还是编成模块(.ko)。

典型写法是这种:

obj-$(CONFIG_FOO) += foo.o

含义:

  • CONFIG_FOO=yfoo.o编进内核镜像(built-in)
  • CONFIG_FOO=mfoo.o会被链接成foo.ko(模块)
  • CONFIG_FOO=n→ 不编译

那么问题来了,这些变量在哪里被设置呢?

—答:在内核根目录.config文件中进行配置,在我们make板卡厂家给的默认配置时,会默认配置.config文件

截取部分.config文件如下:

我们继续提问,这个.config又如何去修改里面的配置参数呢?当然,如果你要手动编写也是无可厚非的,但问题是内核有成千上万个配置选项(CONFIG_*),所以,内核引入了menuconfig。

这个.config文件是由各个驱动目录下的Kconfig文件汇总得到的,只需要修改驱动目录下对应的Kconfig文件,使用make menuconfig可以快速配置.config文件的参数内容。

menuconfig 是 Linux 内核 Kconfig 配置系统提供的一个交互式(终端界面)配置工具。它的核心目的很简单:让你用“菜单”的方式生成/修改内核的 .config,从而决定内核和各类驱动/子系统到底编译进内核(y)、编译成模块(m)还是不编译(n)。其界面如下:

在执行make menuconfig指令的时候一定要确定好自己的编译平台和交叉编译链工具是否正确,否则在部署到板卡上后很有可能会产生错误。例如在rk3588上是如下配置的:

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig

menuconfig常用的快捷键如下

  • /:搜索配置项(强烈推荐)
    • 输入关键字或CONFIG_名称,能直接定位选项所在菜单
  • ?:查看当前选项帮助信息(help)
  • y / n / m:直接把当前项设为 y/n/m
  • Space:循环切换状态(n → m → y)
  • Esc:返回/退出

技巧:找不到某个驱动选项时,先按 / 搜它,再根据搜索结果跳转到对应菜单。

下面我们使用一个实例进行强化:

我们当前完成了一个简单驱动程序模块:

#include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> static int __init hello_init(void) { printk(KERN_EMERG "[ KERN_EMERG ] Hello Module Init\\n"); printk( "[ default ] Hello Module Init\\n"); return 0; } static void __exit hello_exit(void) { printk("[ default ] Hello Module Exit\\n"); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL2"); MODULE_AUTHOR("cc "); MODULE_DESCRIPTION("hello world module"); MODULE_ALIAS("test_module");

我们将程序放入内核drivers/char目录下

在当前目录下的Makefile文件中,我们配置模块参数

在当前目录的Kconfig文件中,编写模块的Kconfig信息

此处的状态可以设置为bool(y或n)或者tristate(三态,y、n、m,m表示为一个模块)

然后在内核根目录执行make menuconfig,使用/搜索HELLO_MODULE可以看到如下:

在.config文件中搜索HELLO_MODULE可以看到参数已经配置成y

如果想要配置成默认为n,也可以在menuconfig中配置

至此,介绍完了两种编译方式,大家可以自行尝试加深理解。

参考资料

  • Linux下menuconfig与Kconfig基础知识概要
  • 韦东山Linux驱动课程
  • 内核参考文档
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 22:24:58

vue.3

1.局部注册只能在注册的组件内使用&#xff08;1&#xff09;创建vue文件&#xff08;2&#xff09;在使用的组件内导入并注册2.全局注册所有组件内都能使用&#xff08;1&#xff09;创建vue文件&#xff08;2&#xff09;main.js中进行全局注册3.组件的样式冲突scoped全局注册…

作者头像 李华
网站建设 2026/4/21 16:06:30

centos7-nvidia驱动安装及简单测试

centos7-nvidia驱动安装类别信息服务器型号Rack Mount Chassis NF5280M6CPUIntel Xeon Silver 4310 CPU 2.10GHz * 2系统版本Centos 7系统内核版本3.10.0-1160.el7.x86_64GPU型号NVIDIA A100&#xff08;40G&#xff09;*4Nvidia版本525.85.05CUDA版本12.0.0docker版本20.10.9…

作者头像 李华
网站建设 2026/4/23 13:59:08

BUCK-BOOST升降压电路Multisim电路仿真分析

目录 0 概述 工作过程简述 Q1 导通阶段 Q1 关断阶段 稳态输出 主要元件作用 电路特点 1 过程分析: 第一次开关闭合时 第二次Q1闭合时C1放电 2 Multisim仿真分析 占空比D=25% 占空比D=60% 摘要 本文分析了三极管型BUCK-BOOST升降压开关电源的工作原理。该电路结…

作者头像 李华
网站建设 2026/4/19 16:23:11

内存固态等大幅涨价的优势是什么?

原本电子垃圾又有了些许价值升华。 排名上升 现在有部分旧电脑重新启用。看大数据的排名结果&#xff1a; https://blog.csdn.net/ZhangRelay/article/details/155345614 这是去年&#xff0c;2025年11月28日测试的结果&#xff0c;2%排位&#xff0c;非常低端了。 预料之中的…

作者头像 李华
网站建设 2026/4/25 17:58:05

YOLOv12官版镜像训练全流程,附完整代码示例

YOLOv12官版镜像训练全流程&#xff0c;附完整代码示例 YOLOv12不是迭代编号的简单延续&#xff0c;而是一次范式跃迁——它彻底告别了卷积主干&#xff0c;将注意力机制作为目标检测的原生语言。当行业还在为RT-DETR的推理延迟发愁时&#xff0c;YOLOv12已用1.6毫秒完成一次高…

作者头像 李华