1. 课程导论与实验环境搭建

各位同学好,我是你们这门课的老张。做嵌入式Linux内核开发有些年头了,踩过的坑比吃过的盐还多(笑)。今天咱们开始第一讲,先把地基打牢。

嵌入式Linux开发,说白了就是让Linux跑在资源受限的硬件上。你想想看,一个路由器、一个智能摄像头、一块工业控制板,它们的内存可能只有32MB、64MB,Flash也就16MB。标准Linux内核动辄几百MB,直接放上去?门儿都没有。

所以就有了内核裁剪这回事。我2015年做一个工业网关项目,硬件选型时为了省5块钱成本,选了颗只有8MB Flash的芯片。结果标准内核编译完12MB,死活塞不进去。那会儿我连续熬了三个通宵,把内核里用不到的驱动、文件系统、网络协议栈一层层扒掉,最后压到6.8MB。嗯,从那以后,我对内核裁剪的理解就完全不一样了。

1.1 嵌入式Linux开发概述

嵌入式Linux开发,和桌面Linux开发最大的区别在于:你得先搞定交叉编译环境。

什么意思?你的开发电脑是x86架构,但目标板可能是ARM、MIPS、RISC-V。你不能直接在x86上编译出ARM能跑的程序——除非你用交叉编译器。

核心概念:交叉编译 = 在宿主机(x86)上编译出目标机(ARM等)可执行的二进制文件。

整个嵌入式Linux系统,从上到下大概分这么几层:

层级 内容 说明
应用层 用户程序、Qt、Busybox 你写的业务逻辑
系统层 C库、工具链、init进程 glibc/uclibc、shell
内核层 Linux内核 + 驱动模块 我们这门课的核心
硬件层 SoC、外设、存储器 你的目标板

我们这门课,主要就盯着「内核层」这一块。怎么把内核变小、变快、变稳定,怎么调试它,怎么让它从开机到跑起你的应用——这些都会讲到。

1.2 内核裁剪的意义

为什么要裁剪内核?我直接给你列几个真实场景:

  • 存储空间不够:很多嵌入式设备的Flash只有4~16MB,标准内核zImage动辄5~10MB,加上根文件系统根本放不下。
  • 启动时间太长:内核里一堆你用不到的驱动,初始化时一个个去探测硬件,白白浪费几百毫秒甚至几秒。工业设备要求上电后1秒内开始干活,你受得了等5秒?
  • 安全性考虑:不需要的模块就是攻击面。把蓝牙、Wi-Fi、USB gadget这些用不到的驱动全删掉,黑客想利用都没门。
  • 实时性要求:内核越小,中断响应越快。我做过一个电机控制项目,内核裁剪前后,中断延迟从120μs降到了35μs。

我的经验:裁剪内核不是盲目删东西。我建议你先用默认配置编译一次,看看zImage多大,然后对照硬件手册,只保留你需要的驱动和功能。每删一个模块,就重新编译测试一次。别一次删太多,出了问题你都不知道是哪个模块引起的。

1.3 搭建交叉编译环境

好,理论说完了,咱们动手。搭建交叉编译环境是第一步,也是最容易出问题的一步。

我个人习惯用Linaro提供的工具链,稳定、更新及时。当然你也可以用Buildroot或Yocto自己编译工具链,但第一节课咱们先别折腾,直接用现成的。

1.3.1 下载交叉编译工具链

以ARM Cortex-A7为例(很多入门级开发板都用这个核):

# 下载ARM gcc工具链
wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz

# 解压到指定目录
tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/

# 添加环境变量
export PATH=/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH

注意:环境变量要加到 ~/.bashrc 或 ~/.zshrc 里,否则每次新开终端都要重新 export。我曾经因为这个浪费了半天时间——编译时总提示找不到编译器,还以为是工具链坏了。

1.3.2 验证工具链

解压完成后,验证一下是否安装成功:

arm-linux-gnueabihf-gcc --version

# 输出应该类似:
# arm-linux-gnueabihf-gcc (Linaro GCC 7.5-2019.12) 7.5.0
# Copyright (C) 2017 Free Software Foundation, Inc.

看到版本号就说明工具链装好了。然后写个简单的测试程序:

# 编写测试代码
echo '#include <stdio.h>
int main() {
    printf("Hello, Embedded Linux!\n");
    return 0;
}' > test.c

# 交叉编译
arm-linux-gnueabihf-gcc -o test test.c

# 查看生成的文件类型
file test
# 输出: test: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3

看到「ARM, EABI5 version 1」就对了。这个文件在x86电脑上跑不了,得放到ARM开发板上才能执行。

1.4 获取内核源码

工具链搞定了,接下来拿内核源码。我建议用LTS(长期支持)版本,稳定、bug少、社区支持好。

1.4.1 从内核官网下载

# 下载Linux 5.10 LTS版本
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.210.tar.xz

# 解压
tar -xvf linux-5.10.210.tar.xz
cd linux-5.10.210

1.4.2 从Git仓库克隆

如果你需要跟踪最新补丁,或者想自己打patch,用Git更方便:

git clone --depth=1 -b v5.10 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
cd linux

--depth=1 表示只克隆最新版本,不下载完整历史。这样速度快很多,大概几十MB就搞定了。

我的习惯:我一般两种方式都保留。官网下载的tar包作为「干净版本」,Git仓库用来做实验和打patch。这样万一改坏了,直接从tar包重新解压一份,不用重新下载。

1.4.3 内核源码目录结构

解压完后,看看里面都有什么:

目录/文件 作用
arch/ 体系结构相关代码(arm、x86、mips等)
drivers/ 设备驱动(占内核代码量60%以上)
fs/ 文件系统实现(ext4、fat、nfs等)
net/ 网络协议栈
kernel/ 核心调度、进程管理
mm/ 内存管理
include/ 头文件
scripts/ 编译脚本、配置工具
Makefile 顶层编译规则
Kconfig 内核配置菜单定义

后面几节课,我们会频繁进出 arch/arm/、drivers/、kernel/ 这些目录。你现在先有个印象就行。

1.5 本章知识体系

我把这一章的核心逻辑画了张图,方便你理解整个流程:

第一章 知识体系与实验流程 嵌入式Linux内核裁剪调试环境 交叉编译工具链 Linux内核源码 目标硬件平台 下载Linaro工具链 配置环境变量 验证交叉编译器 下载LTS版本内核 tar解压或Git克隆 熟悉目录结构 ARM Cortex-A7等 确认Flash/RAM大小 确定外设列表 可以开始内核配置与裁剪 三个模块缺一不可:没有工具链编译不了,没有源码改什么,不了解硬件裁什么?

这张图把第一章的脉络理清楚了。你照着这个流程走,环境搭建就不会乱。

1.6 本章小结

好,第一节课的内容就这些。咱们捋一下:

  • 嵌入式Linux开发的核心是交叉编译,你得先搞定工具链
  • 内核裁剪是为了省空间、提速度、保安全
  • 交叉编译环境搭建不难,但环境变量一定要配好
  • 内核源码推荐用LTS版本,下载后先熟悉目录结构

下节课,咱们就要开始真正的内核配置了。我会带你用 make menuconfig 一个个菜单看过去,告诉你哪些可以关、哪些必须开。到时候你拿着今天搭好的环境,直接上手操作。

有什么问题,先自己查查资料,实在搞不定咱们课上再聊。动手试试,别光看不练——代码这东西,敲一遍比看十遍都管用。