title: "Linux内核编译与配置" tags:
Linux内核版本号由三个数字组成:主版本.次版本.修订号。例如Linux 4.1.15,其中:
4:主版本号,重大架构变更时递增1:次版本号,奇数表示开发版,偶数表示稳定版15:修订号,bug修复和小功能更新查看内核版本:
uname -r
# 输出示例:4.1.15-gb39c1d0
Linux内核源码主要目录结构如下:
linux-4.1.15/
├── arch/ # 架构相关代码(ARM、x86等)
├── block/ # 块设备驱动
├── crypto/ # 加密算法
├── Documentation/ # 内核文档
├── drivers/ # 设备驱动
├── fs/ # 文件系统
├── include/ # 头文件
├── init/ # 内核初始化
├── ipc/ # 进程间通信
├── kernel/ # 内核核心
├── lib/ # 库函数
├── mm/ # 内存管理
├── net/ # 网络协议栈
├── scripts/ # 构建脚本
├── security/ # 安全模块
├── sound/ # 音频驱动
└── Makefile # 顶层Makefile
Linux内核使用Kconfig配置系统,主要文件包括:
Kconfig:配置项定义Makefile:编译规则defconfig:默认配置文件配置流程:Kconfig → menuconfig → .config → 编译
Kconfig是Linux内核的配置描述语言,定义在各子目录的Kconfig文件中。
config 选项名称
类型(bool/tristate/int/hex/string)
"提示信息"
默认值
依赖关系
帮助文本
| 类型 | 说明 | 取值 |
|---|---|---|
bool |
布尔类型 | y或n |
tristate |
三态类型 | y、n或m(模块) |
int |
整数类型 | 数字 |
hex |
十六进制 | 0x格式数字 |
string |
字符串 | 任意字符串 |
# 定义配置项
config LED_DRIVER
bool "LED Driver"
default y
# 三态类型(可编译为模块)
config USB_STORAGE
tristate "USB storage support"
default m
# 整数类型
config NR_CPUS
int "Maximum number of CPUs"
range 2 8
default 4
# 依赖关系
config HIGHMEM
bool "High Memory Support"
depends on ARM
# 反向依赖
config FB
bool "Support for frame buffer"
depends on !S390
# 选择依赖
config SND_SOC
tristate "ALSA SoC support"
select SND_PCM
# 多选依赖
config EXT4_FS
tristate "Ext4 file system"
depends on BLOCK
# 创建菜单
menu "Device Drivers"
source "drivers/Kconfig"
endmenu
# 创建子菜单
menu "Network device support"
menu "Ethernet driver support"
source "drivers/net/ethernet/Kconfig"
endmenu
endmenu
# 条件菜单
if ARCH_ARM
menu "ARM specific configuration"
endmenu
endif
依赖关系是Kconfig的核心机制,确保配置选项的逻辑正确性。
# depends on - 必须满足
config MODULE_UNLOAD
bool "Module unloading"
depends on MODULES
# ! 取反
config LOCALVERSION
string "Local version - append to kernel release"
depends on !COMPILE_TEST
# || 或
config SND
tristate "Sound card support"
depends on AUDIT || !AUDIT
# && 与
config X86_64
bool "64-bit kernel"
depends on 64BIT && X86
# 选择依赖(自动选择被依赖项)
config SND_SOC
tristate "ALSA SoC support"
select SND_PCM
# 反向选择
config SND_SOC_I2S
tristate "Generic I2S driver"
select SND_SOC
make menuconfig是基于ncurses的图形配置界面。
# 基本使用
make menuconfig
# 交叉编译配置
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
# 使用外部分支配置
make ARCH=arm menuconfig O=out/
配置界面操作:
y:编译进内核m:编译为模块n:不编译?:查看帮助/:搜索配置项Esc Esc:返回上级顶层Makefile开头定义内核版本号:
# 版本定义
VERSION = 4
PATCHLEVEL = 1
SUBLEVEL = 15
EXTRAVERSION =
# 自动生成版本信息
KERNELVERSION = $(VERSION)$(PATCHLEVEL)$(SUBLEVEL)$(EXTRAVERSION)
# 递归编译标志
MAKEFLAGS += -rR --include-dir=$(CURDIR)
-r禁止内置规则,-R禁止内置变量,提高编译效率。
# V=1 显示详细编译命令
ifeq ("$(origin V)", "command line")
KBUILD_VERBOSE = $(V)
endif
ifndef KBUILD_VERBOSE
KBUILD_VERBOSE = 0
endif
ifeq ($(KBUILD_VERBOSE),1)
quiet =
Q =
else
quiet=quiet_
Q = @
endif
export quiet Q KBUILD_VERBOSE
使用方法:
make V=0:静默输出(默认)make V=1:显示完整编译命令# make -s 静默模式
ifneq ($(filter 4.%,$(MAKE_VERSION)),) # make-4
ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
quiet=silent_
endif
else # make-3.8x
ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
quiet=silent_
endif
endif
# O=xxx 指定输出目录
ifeq ($(KBUILD_SRC),)
ifeq ("$(origin O)", "command line")
KBUILD_OUTPUT := $(O)
endif
endif
使用方法:
make O=out/linux # 编译输出到out/linux目录
# C=1 检查需要重新编译的文件
# C=2 检查所有源文件
ifeq ("$(origin C)", "command line")
KBUILD_CHECKSRC = $(C)
endif
ifndef KBUILD_CHECKSRC
KBUILD_CHECKSRC = 0
endif
# M=dir 编译外部模块
ifdef SUBDIRS
KBUILD_EXTMOD ?= $(SUBDIRS)
endif
ifeq ("$(origin M)", "command line")
KBUILD_EXTMOD := $(M)
endif
# 外部模块时,目标为modules
ifeq ($(KBUILD_EXTMOD),)
_all: all
else
_all: modules
endif
使用方法:
make M=/path/to/module # 编译外部模块
ifeq ($(KBUILD_SRC),)
srctree := .
else
ifeq ($(KBUILD_SRC)/,$(dir $(CURDIR)))
srctree := ..
else
srctree := $(KBUILD_SRC)
endif
endif
objtree := .
src := $(srctree)
obj := $(objtree)
VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))
export srctree objtree VPATH
# 架构类型
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)
实际使用时需要修改为:
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-gnueabihf-
或者通过命令行指定:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- xxx_defconfig
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
USERINCLUDE := \
-I$(srctree)/arch/$(hdr-arch)/include/uapi \
-Iarch/$(hdr-arch)/include/generated/uapi \
-I$(srctree)/include/uapi \
-Iinclude/generated/uapi \
-include $(srctree)/include/linux/kconfig.h
LINUXINCLUDE := \
-I$(srctree)/arch/$(hdr-arch)/include \
-Iarch/$(hdr-arch)/include/generated/uapi \
-Iarch/$(hdr-arch)/include/generated \
$(if $(KBUILD_SRC), -I$(srctree)/include) \
-Iinclude \
$(USERINCLUDE)
export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION
export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC
export CPP AR NM STRIP OBJCOPY OBJDUMP
export MAKE AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE
export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS
export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KASAN
export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
export KBUILD_ARFLAGS
首次编译前需要使用make xxx_defconfig配置内核:
# 使用默认配置
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig
# 配置目标匹配
%config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
执行流程:
make xxx_defconfig
↓
scripts_basic (编译fixdep、bin2c工具)
↓
scripts/kconfig/conf --defconfig=arch/arm/configs/xxx_defconfig Kconfig
↓
生成.config文件
图形化配置界面:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
配置文件位置:
arch/arm/configs/xxx_defconfig.config# 使用架构默认配置
make ARCH=arm defconfig
# 使用厂商提供的配置
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig
# 方式1:基于现有配置修改
make menuconfig
# 在菜单中修改配置,保存后生成.config
# 方式2:手动编辑.config
vim .config
make olddefconfig # 更新配置
# 方式3:备份和恢复配置
cp .config .config.backup
make defconfig
cp .config.backup .config
make olddefconfig
# 编译zImage
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage
# 编译所有(包括模块)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all
# 使用16线程并行编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16
# make all 目标
all: vmlinux
# BOOT_TARGETS定义
BOOT_TARGETS = zImage Image xipImage bootpImage uImage
$(BOOT_TARGETS): vmlinux
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
# vmlinux依赖
vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)
# 链接命令
cmd_link-vmlinux = $(CONFIG_SHELL) $< $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux)
vmlinux组成部分:
| 组成 | 说明 | 路径 |
|---|---|---|
| head-y | 启动代码 | arch/arm/kernel/head.o |
| init-y | 初始化代码 | init/built-in.o |
| core-y | 核心代码 | kernel/mm/fs/ipc等 |
| libs-y | 库函数 | lib/lib.a lib/built-in.o |
| drivers-y | 设备驱动 | drivers/sound/firmware |
| net-y | 网络协议 | net/built-in.o |
| 镜像 | 大小 | 说明 |
|---|---|---|
| vmlinux | ~16MB | ELF格式,未压缩 |
| Image | ~12MB | 去除调试信息 |
| zImage | ~6MB | gzip压缩 |
| uImage | ~6MB | U-Boot专用格式 |
转换关系:
vmlinux → objcopy → Image → gzip → zImage → mkimage → uImage
# 编译后修改代码,直接执行
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16
# 清理编译产物
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- clean
# 完全清理(包括.config)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mrproper
在Kconfig中使用obj-y编译进内核:
# drivers/leds/Kconfig
config LEDS_GPIO
tristate "GPIO LED driver"
depends on LEDS_CLASS
default y
# drivers/leds/Makefile
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
# 编译外部模块
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- M=/path/to/module modules
# 安装模块到指定目录
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- M=/path/to/module \
INSTALL_MOD_PATH=/path/to/rootfs modules_install
# 外部模块Makefile
obj-m := mydriver.o
mydriver-objs := main.o init.o
KERNEL_DIR := /path/to/linux-4.1.15
CROSS_COMPILE := arm-linux-gnueabihf-
ARCH := arm
all:
make -C $(KERNEL_DIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) \
M=$(PWD) modules
clean:
make -C $(KERNEL_DIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) \
M=$(PWD) clean
# 将模块复制到内核模块目录
cp mydriver.ko /lib/modules/4.1.15/kernel/drivers/
# 生成模块依赖
depmod -a
# 加载模块
insmod mydriver.ko
# 查看已加载模块
lsmod
| 对比项 | I.MX6ULL | STM32MP1 | RK3568 |
|---|---|---|---|
| 内核版本 | 4.1.15 | 5.4 | 5.10 |
| 架构 | ARM Cortex-A7 | ARM Cortex-A7 | ARM Cortex-A55 |
| 位数 | 32位 | 32位 | 64位 |
| 配置文件 | imx_v7_defconfig | stm32mp1_defconfig | rockchip_linux_defconfig |
| 设备树 | imx6ull-14x14-evk.dts | stm32mp157c-ev1.dts | rk3568-evb1-v10.dts |
| 内核大小 | ~5MB | ~6MB | ~8MB |
| 启动方式 | U-Boot+zImage | U-Boot+zImage | U-Boot+zImage |
# I.MX6ULL (ARM 32位)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig
# STM32MP1 (ARM 32位)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- stm32mp1_defconfig
# RK3568 (ARM 64位)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- rockchip_linux_defconfig
| 驱动类型 | I.MX6ULL | STM32MP1 | RK3568 |
|---|---|---|---|
| GPIO | gpio-mxc | gpio-stm32 | gpio-rockchip |
| I2C | i2c-imx | i2c-stm32 | i2c-rk3x |
| SPI | spi-imx | spi-stm32 | spi-rockchip |
| UART | serial-imx | serial-stm32 | serial-rockchip |
答案:
make xxx_defconfig或make menuconfig生成.config文件arch/arm/Makefile设置架构相关变量scripts/link-vmlinux.sh链接生成vmlinux答案:
depends on:配置项被依赖,必须满足条件才能启用
config HIGHMEM
bool "High Memory Support"
depends on ARM # 只有ARM架构才能选择
select:配置项被选中时自动选择被依赖项
config SND_SOC
tristate "ALSA SoC support"
select SND_PCM # 选中时自动选中SND_PCM
答案: vmlinux通过链接脚本和链接命令生成:
答案:
make xxx_defconfig:使用预定义的默认配置文件快速配置,适合初始配置
make ARCH=arm imx_v7_defconfig # 使用IMX6ULL默认配置
make menuconfig:提供图形界面手动修改配置,适合定制化需求
make ARCH=arm menuconfig # 打开配置菜单
推荐流程:先用defconfig快速配置,再用menuconfig精细调整
答案:
# 1. 进入内核源码目录
cd /path/to/linux-4.1.15
# 2. 配置内核
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
# 3. 编译内核
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16
# 4. 编译模块
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules
# 5. 安装模块到rootfs
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- \
INSTALL_MOD_PATH=/path/to/rootfs modules_install
# 6. 复制zImage到TFTP目录
cp arch/arm/boot/zImage /tftpboot/
# 7. 复制设备树到TFTP目录
cp arch/arm/boot/dts/imx6ull-14x14-evk.dtb /tftpboot/
# 8. 在U-Boot中设置启动参数
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait'
setenv bootcmd 'tftp ${loadaddr} zImage; tftp ${fdt_addr} imx6ull-14x14-evk.dtb; bootz ${loadaddr} - ${fdt_addr}'
saveenv
run bootcmd