2. 开发环境准备:安装交叉编译工具链、配置主机环境、创建项目目录结构
做嵌入式Linux开发,第一件事就是把开发环境搭好。这步要是没弄对,后面编译出来的东西跑不起来,你都不知道问题出在哪。我刚开始做嵌入式那会儿,就吃过这个亏——交叉编译工具链版本不对,折腾了两天才发现是glibc不兼容。
说白了,嵌入式开发环境和PC开发最大的区别就是:你得在PC上编译,在目标板上运行。这就需要一个叫「交叉编译工具链」的东西。咱们一步步来。
2.1 主机环境要求
我个人习惯用Ubuntu 20.04 LTS或22.04 LTS做宿主机。为什么?因为社区支持好,包管理方便,遇到问题搜一下就有答案。
| 项目 | 推荐配置 | 最低要求 |
|---|---|---|
| 操作系统 | Ubuntu 22.04 LTS (64-bit) | Ubuntu 20.04 LTS |
| CPU | 4核及以上 | 双核 |
| 内存 | 8GB及以上 | 4GB |
| 磁盘空间 | 50GB空闲 | 20GB |
| 网络 | 稳定互联网连接 | 可下载软件包 |
2.2 安装交叉编译工具链
交叉编译工具链,你可以理解成「翻译官」——它把你的x86指令翻译成ARM指令。咱们课程用的是ARM Cortex-A7架构,所以需要安装arm-linux-gnueabihf工具链。
安装方式有两种,我推荐第二种:
方式一:apt直接安装(简单但版本旧)
sudo apt update
sudo apt install gcc-arm-linux-gnueabihf binutils-arm-linux-gnueabihf
这种方式装完就能用,但版本通常比较老。我记得有一次用apt装了个gcc 7.x,结果编译新版本内核时一堆语法错误……从那以后我就改用第二种方式了。
方式二:Linaro工具链(推荐)
Linaro的ARM工具链更新及时,优化也好。咱们用gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf这个版本,稳定且兼容性好。
# 下载工具链
wget https://releases.linaro.org/components/toolchain/binaries/7.5-2019.12/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
# 解压到指定目录
sudo tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/
# 添加环境变量
echo 'export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin' >> ~/.bashrc
source ~/.bashrc
验证安装
装完之后,跑一下这个命令:
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.
2.3 安装必要的主机工具
除了交叉编译器,咱们还需要一些辅助工具。这些工具在构建根文件系统和调试时都会用到。
sudo apt install -y \
build-essential \
git \
vim \
curl \
wget \
libncurses5-dev \
libssl-dev \
bison \
flex \
u-boot-tools \
device-tree-compiler \
qemu-user-static \
debootstrap
这里我重点说几个:
- libncurses5-dev:编译内核时make menuconfig必须的
- device-tree-compiler:编译设备树.dtb文件用的
- qemu-user-static:可以在PC上模拟运行ARM程序,调试利器
2.4 创建项目目录结构
好,工具链和主机环境都准备好了。接下来咱们搭项目骨架。一个清晰的项目结构,能让你少走很多弯路。我见过太多人把所有文件堆在一个目录里,最后自己都找不着北。
我个人习惯用这样的结构:
~/embedded-linux-course/
├── toolchain/ # 交叉编译工具链(或软链接)
├── kernel/ # Linux内核源码
├── bootloader/ # U-Boot源码
├── rootfs/ # 根文件系统构建目录
│ ├── source/ # 源码包(BusyBox、glibc等)
│ ├── output/ # 编译输出
│ └── target/ # 目标根文件系统目录
├── images/ # 最终镜像文件
├── scripts/ # 自动化构建脚本
└── docs/ # 笔记和文档
创建命令:
mkdir -p ~/embedded-linux-course/{toolchain,kernel,bootloader,rootfs/{source,output,target},images,scripts,docs}
你可能会问:为什么要把rootfs拆成source、output、target三个子目录?
嗯,这里解释一下:
- source:放BusyBox、glibc等源码包,保持原始状态
- output:编译产生的中间文件,随时可以删掉重来
- target:最终组装好的根文件系统目录,直接打包就能用
这样分层,你想想看——调试时只需要重新编译某个组件,其他部分不受影响。
2.5 验证环境:写个Hello World
环境搭没搭好,跑个程序就知道了。咱们写个简单的C程序,用交叉编译器编译,再用qemu模拟运行。
# 创建测试文件
cat > ~/embedded-linux-course/test_arm.c << 'EOF'
#include <stdio.h>
int main() {
printf("Hello from ARM!\n");
printf("Cross-compilation works!\n");
return 0;
}
EOF
# 交叉编译
arm-linux-gnueabihf-gcc -static -o test_arm test_arm.c
# 查看文件信息
file test_arm
如果输出是ELF 32-bit LSB executable, ARM,说明交叉编译成功了。
再用qemu跑一下:
qemu-arm-static ./test_arm
看到Hello from ARM!,恭喜你,环境全部就绪。
-static参数,会把所有库静态链接进去。这样在qemu里跑就不用额外挂载动态库了,调试起来特别方便。
2.6 本章知识结构图
下面这张图帮你理清整个开发环境的脉络:
2.7 常见问题与解决
最后,我把这些年遇到的环境问题整理了一下:
| 问题现象 | 原因 | 解决办法 |
|---|---|---|
| arm-linux-gnueabihf-gcc: command not found | 环境变量没配置或路径不对 | 检查PATH是否包含工具链bin目录,重新source ~/.bashrc |
| 编译时报错:/usr/bin/ld: cannot find -lc | 缺少C库或库路径不对 | 检查工具链是否完整,重新解压安装 |
| qemu运行报错:Invalid ELF image for this architecture | 编译架构和qemu模拟架构不匹配 | 确认编译时用的是arm-linux-gnueabihf-gcc,不是gcc |
| make menuconfig报错:Unable to find the ncurses libraries | 缺少libncurses5-dev | sudo apt install libncurses5-dev(22.04用libncurses-dev) |