一、内核编译系统详解
1.1 Makefile系统
1.1.1 内核Makefile结构
Linux内核源码目录结构:
arch/ - 架构相关代码
drivers/ - 设备驱动
fs/ - 文件系统
include/ - 头文件
init/ - 初始化代码
kernel/ - 核心内核
mm/ - 内存管理
net/ - 网络协议
1.1.2 配置变量系统
Makefile中的配置变量:
# 示例:drivers/char/Makefile中的配置
obj-$(CONFIG_MAIN) += main.o
obj-$(CONFIG_FUN1_MEMORY) += fun1.o
obj-$(CONFIG_FUN2_NET) += fun2.o
# 链接规则
$(TARGET): $(OBJ)
gcc $^ -o $@
变量说明:
-
obj-y:编译进内核(built-in) -
obj-m:编译为模块(module) -
obj-n:不编译 -
obj-:总是编译(无条件)
.config文件示例:
CONFIG_MAIN=y
CONFIG_FUN1_MEMORY=y
CONFIG_FUN2_NET=y
CONFIG_DEMO_DRIVER=m
1.1.3 自动变量
$@ - 目标文件名
$< - 第一个依赖文件名
$^ - 所有依赖文件
$? - 比目标新的依赖文件
$* - 不包含扩展名的目标文件
1.2 内核编译流程
1.2.1 完整编译步骤
所有命令均在Linux内核源码的顶层目录执行
步骤1:获取内核源码
# 拷贝内核源码压缩包到Ubuntu
# 假设文件名为:linux-4.1.15.tar.xz
步骤2:解压内核源码
sudo tar -xvf linux-4.1.15.tar.xz
# 修改源码目录权限(建议)
sudo chmod 0777 linux-4.1.15 -R
# 或
sudo chown -R $(whoami):$(whoami) linux-4.1.15
步骤3:应用默认配置
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_alientek_emmc_defconfig
命令参数说明:
-
ARCH=arm:指定ARM架构 -
CROSS_COMPILE=arm-linux-gnueabihf-:指定交叉编译器前缀 -
imx_alientek_emmc_defconfig:i.MX6开发板的默认配置文件
步骤4:配置内核模块
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
menuconfig界面操作:
键盘操作:
↑↓ - 上下移动
Enter - 进入子菜单/确认选择
Y - 编译进内核
M - 编译为模块
N - 不编译
/ - 搜索配置项
? - 查看帮助
ESC ESC - 返回/退出
步骤5:编译内核
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16
参数说明:
-
all:编译所有内容(zImage、模块、设备树) -
-j16:使用16个线程并行编译(根据CPU核心数调整)
步骤6:获取编译结果
# 内核镜像位置
arch/arm/boot/zImage
# 设备树文件位置
arch/arm/boot/dts/*.dtb
# 内核模块位置
各个驱动目录下的*.ko文件
步骤7:部署验证
# 拷贝到TFTP服务目录
cp arch/arm/boot/zImage /tftpboot/
cp arch/arm/boot/dts/imx6ull-alientek-emmc.dtb /tftpboot/imx6.dtb
1.3 内核镜像格式
1.3.1 三种内核镜像
1. Image
-
原始的内核镜像
-
未经压缩,可以直接执行
-
文件最大
-
位置:
arch/arm/boot/Image
2. zImage
-
压缩的内核镜像
-
结构:解压程序 + 压缩的Image
-
最常用格式
-
位置:
arch/arm/boot/zImage
3. uImage
-
U-Boot专用的内核镜像
-
结构:64字节的头信息 + zImage
-
包含加载地址、入口地址等信息
-
位置:
arch/arm/boot/uImage
1.3.2 镜像生成关系
vmlinux(ELF格式) → Image(原始二进制) → zImage(压缩) → uImage(U-Boot格式)
1.4 Kconfig配置系统
1.4.1 Kconfig作用
-
定义
make menuconfig中的配置选项 -
管理内核功能模块的编译选项
-
生成
.config配置文件
1.4.2 Kconfig语法
基本语法元素:
config SYMBOL # 配置选项
bool "描述" # 布尔类型选项
default y # 默认值
depends on XXX # 依赖关系
select YYY # 反向依赖
help # 帮助信息
详细的帮助说明
常见类型:
-
bool:布尔类型(y/n) -
tristate:三态(y/m/n) -
int:整数类型 -
string:字符串类型 -
hex:十六进制数
1.4.3 Kconfig示例
config DEMO_DRIVER
tristate "Demo driver support"
default n
help
This is a demo driver for learning.
Say Y to compile it into the kernel.
Say M to compile it as a module.
1.5 向内核添加新文件
1.5.1 添加驱动文件步骤
以向drivers/char目录添加demo.c为例
步骤1:创建驱动源文件
// drivers/char/demo.c
#include <linux/module.h>
#include <linux/init.h>
static int __init demo_init(void)
{
printk(KERN_INFO "Demo driver loaded\n");
return 0;
}
static void __exit demo_exit(void)
{
printk(KERN_INFO "Demo driver removed\n");
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple demo driver");
步骤2:修改Makefile
# drivers/char/Makefile
# 在适当位置添加:
obj-$(CONFIG_DEMO) += demo.o
步骤3:修改Kconfig
# drivers/char/Kconfig
# 在适当位置添加:
config DEMO
bool "Demo driver support"
default n
help
This is a simple demo driver for learning kernel programming.
If unsure, say N.
步骤4:配置内核
# 进入配置界面
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
# 导航到:
# Device Drivers → Character devices → Demo driver support
# 按Y或M选择编译方式
步骤5:编译内核
# 如果编译进内核(Y)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage
# 如果编译为模块(M)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules
# 模块文件位置
# drivers/char/demo.ko
二、交叉编译工具链
2.1 工具链组成
2.1.1 主要工具
arm-linux-gnueabihf-gcc - C编译器
arm-linux-gnueabihf-g++ - C++编译器
arm-linux-gnueabihf-ld - 链接器
arm-linux-gnueabihf-objcopy - 目标文件转换
arm-linux-gnueabihf-objdump - 目标文件反汇编
arm-linux-gnueabihf-readelf - ELF文件查看
arm-linux-gnueabihf-strip - 去除调试信息
2.1.2 工具链命名规则
arm-linux-gnueabihf-
├── arm - 目标架构(ARM)
├── linux - 目标系统(Linux)
├── gnueabi - GNU EABI(嵌入式应用二进制接口)
└── hf - 硬浮点(Hard Float)
2.2 交叉编译使用
2.2.1 编译应用程序
# 编译C程序
arm-linux-gnueabihf-gcc -o hello hello.c
# 带优化选项
arm-linux-gnueabihf-gcc -O2 -o app main.c
# 静态链接
arm-linux-gnueabihf-gcc -static -o app_static main.c
2.2.2 编译内核模块
# 需要指定内核路径
make -C /path/to/kernel M=$(pwd) modules
# 或在内核源码目录编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules
三、开发板与主机通信
3.1 网络配置
3.1.1 静态IP配置
开发板端:
# 临时设置
ifconfig eth0 192.168.1.100 netmask 255.255.255.0 up
# 永久设置(修改配置文件)
# /etc/network/interfaces
auto eth0
iface eth0 inet static
address 192.168.1.100
netmask 255.255.255.0
gateway 192.168.1.1
Ubuntu主机:
# 设置静态IP
sudo vim /etc/netplan/01-network-manager-all.yaml
# 内容示例
network:
version: 2
ethernets:
enp3s0:
addresses: [192.168.1.3/24]
gateway4: 192.168.1.1
nameservers:
addresses: [8.8.8.8, 8.8.4.4]
3.1.2 网络测试
# 开发板ping主机
ping 192.168.1.3
# 主机ping开发板
ping 192.168.1.100
# 查看网络接口
ifconfig
或
ip addr show
四、常见问题解决
4.1 编译问题
4.1.1 编译器找不到
问题:arm-linux-gnueabihf-gcc: command not found
解决:
sudo apt install gcc-arm-linux-gnueabihf
4.1.2 头文件缺失
问题:fatal error: xxx.h: No such file or directory
解决:
# 安装开发包
sudo apt install libxxx-dev
# 或指定包含路径
arm-linux-gnueabihf-gcc -I/path/to/include -o app app.c
4.2 运行问题
4.2.1 动态库缺失
问题:./app: error while loading shared libraries: libxxx.so: cannot open shared object file
解决:
# 在开发板安装库文件
# 或静态链接
arm-linux-gnueabihf-gcc -static -o app app.c
4.2.2 权限问题
问题:Permission denied
解决:
# 添加执行权限
chmod +x app
# 或使用root权限
sudo ./app