驱动编译成模块和*区别

一、最核心

*(=y)是“焊死在内核里”
M(=m)是“可插拔的外设模块”

二、编译层面的本质区别(非常重要)

1️⃣ =y(*) —— 内核的一部分

CONFIG_FOO=y

意味着:

源码被编译进:

vmlinux
Image / zImage

和内核一起 同时存在、同时启动
不能卸载
不依赖 userspace

📌 编译结果:

vmlinux 内有 foo_driver.o

2️⃣ =m(M) —— 可加载模块

CONFIG_FOO=m

意味着:
驱动编译成一个 .ko 文件
放在:
/lib/modules/$(uname -r)/foo.ko

需要 modprobe / insmod 才会生效
可以卸载

📌 编译结果:

foo.ko

三、启动阶段的决定性差异(嵌入式最关键)

❌ 模块在内核早期是“不可用的”

凡是和启动相关的驱动,必须 =y

包括:

MMC / eMMC / NAND
EXT4 / UBIFS
I2C / SPI(如果 rootfs 在上面)
LCD / 串口(调试)

四、真实工程中的选型原则(非常实用)

✅ 必须 =y 的驱动

类型 原因
RootFS 所在设备 启动前必须可用
控制台串口 否则你啥都看不到
pinctrl / clock SoC 基础设施
Device Tree 支持 ARM 必须

✅ 适合 =m 的驱动

类型 原因
USB 设备 插拔式
摄像头 可选
声卡 可替换
WiFi / BT 固件加载慢

五、M 和 Y 在 Kconfig 里的隐藏规则(很重要)

1️⃣ 模块不能依赖内置的反向关系

A = m
B depends on A

→ B 不能是 y,最多 m

所以有规则:

依赖链中,最“弱”的那个决定上限

2️⃣ select 会强制拉成 y(危险)

config A
  select B

即使你没开 B
也会被强行设为 y

posted @ 2026-01-14 20:11  上善若淼  阅读(3)  评论(0)    收藏  举报