学习笔记——Linux内核与嵌入式开发3
本文详细介绍了Linux内核编译系统与ARM开发的关键技术要点。主要内容包括:1)内核Makefile结构、配置变量系统和自动变量使用;2)完整的内核编译流程,从源码获取到部署验证;3)内核镜像格式(Image/zImage/uImage)及其生成关系;4)Kconfig配置系统的语法与使用方法;5)向内核添加新驱动文件的完整步骤;6)交叉编译工具链的组成与命名规则;7)开发板与主机的网络配置方法
一、内核编译系统详解
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
更多推荐
所有评论(0)