第二章 嵌入式开发环境搭建

说实话,嵌入式开发最让人头疼的往往不是写代码本身,而是环境搭建。我见过太多新手,甚至有些老手,在环境配置上浪费一整天。今天我就把这几年的经验梳理一下,帮你少走些弯路。

2.1 交叉编译工具链安装

交叉编译,说白了就是在你的电脑上编译出能在ARM板子上跑的程序。为什么不能直接在板子上编译?因为板子性能太弱了,编译个Linux内核可能要等半天。

核心概念:交叉编译工具链 = 编译器 + 链接器 + 库文件 + 调试工具

我个人习惯用Linaro提供的工具链,稳定且更新及时。安装步骤其实很简单:

# 下载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 -xf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/

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

小技巧:建议把环境变量写到 ~/.bashrc 里,这样每次打开终端就不用重新设置了。我刚开始时忘了这步,每次都要手动export,烦得很。

验证是否安装成功:

arm-linux-gnueabihf-gcc --version
# 如果看到版本信息,说明安装成功

写个简单的测试程序试试:

// hello.c
#include <stdio.h>

int main() {
    printf("Hello, Embedded World!\n");
    return 0;
}

// 编译
arm-linux-gnueabihf-gcc -o hello hello.c

// 查看文件信息
file hello
# 输出: hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV)

看到ARM字样,说明编译成功了。嗯,这里要注意:如果你的宿主机是64位,可能需要安装32位兼容库,否则会报错。

我曾经踩过的坑:有一次我下载了错误的架构版本,比如板子是armv7,我下了armv8的工具链。编译出来的程序在板子上直接段错误。所以一定要确认你的目标架构。

2.2 嵌入式Linux系统构建

构建嵌入式Linux系统,说白了就是给板子做一个最小化的操作系统。我推荐用Buildroot,它比Yocto简单太多了。

为什么选Buildroot?你想想看,Yocto第一次构建要下载几十G的东西,编译几个小时。Buildroot轻量多了,适合快速验证。

# 下载Buildroot
git clone git://git.buildroot.net/buildroot
cd buildroot

# 配置
make menuconfig

# 关键配置项:
# Target options -> Target Architecture -> ARM (little endian)
# Target options -> Target Architecture Variant -> cortex-a7
# Toolchain -> Toolchain type -> External toolchain
# System configuration -> Root filesystem overlay directory

# 开始构建
make -j4

构建完成后,在 output/images 目录下会生成:

文件 说明
zImage 压缩后的内核镜像
rootfs.ext4 根文件系统
vexpress-v2p-ca9.dtb 设备树文件

个人经验:第一次构建时,建议只选最基本的包。我见过有人一股脑选了所有包,结果编译了3小时,最后发现很多都用不上。先跑起来,再慢慢加功能。

2.3 QEMU模拟器配置

没有板子怎么办?用QEMU模拟。我在项目中经常先用QEMU验证,没问题了再烧到真板子上。这样调试效率高很多。

# 安装QEMU
sudo apt-get install qemu-system-arm

# 启动模拟器
qemu-system-arm \
    -M vexpress-a9 \
    -kernel zImage \
    -dtb vexpress-v2p-ca9.dtb \
    -drive file=rootfs.ext4,if=sd,format=raw \
    -append "console=ttyAMA0 root=/dev/mmcblk0" \
    -nographic

启动后你会看到Linux启动日志,最后出现登录提示符。默认用户名root,密码空。

调试技巧:加上 -s 参数可以启动GDB调试服务,然后用 arm-linux-gnueabihf-gdb 远程连接。我调试驱动时经常这么干。

网络配置也很重要:

# 使用tap网络,让QEMU和宿主机互通
qemu-system-arm \
    -M vexpress-a9 \
    -kernel zImage \
    -dtb vexpress-v2p-ca9.dtb \
    -drive file=rootfs.ext4,if=sd,format=raw \
    -append "console=ttyAMA0 root=/dev/mmcblk0" \
    -net nic -net tap,ifname=tap0 \
    -nographic

注意:使用tap网络需要root权限,而且要先创建tap接口。我建议用脚本自动化这个过程,不然每次都要手动敲命令。

2.4 版本控制工具Git与GitLab部署

版本控制是DevOps的基石。Git大家都熟,但嵌入式项目有它的特殊性——二进制文件多、编译产物大、依赖管理复杂。

我建议的Git工作流:

  1. 主分支(main):只放稳定版本,每次提交都要经过CI测试
  2. 开发分支(develop):日常开发,允许小问题
  3. 功能分支(feature/*):每个新功能一个分支
  4. 发布分支(release/*):准备发布时创建
# 初始化仓库
git init
git add .
git commit -m "Initial commit: embedded project skeleton"

# 添加.gitignore,忽略编译产物
echo "build/
*.o
*.elf
*.bin
output/" > .gitignore

# 创建开发分支
git checkout -b develop

GitLab部署我用Docker,简单快速:

# docker-compose.yml
version: '3'
services:
  gitlab:
    image: gitlab/gitlab-ce:latest
    restart: always
    hostname: 'gitlab.example.com'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://gitlab.example.com'
    ports:
      - '80:80'
      - '443:443'
      - '22:22'
    volumes:
      - './gitlab/config:/etc/gitlab'
      - './gitlab/logs:/var/log/gitlab'
      - './gitlab/data:/var/opt/gitlab'

部署经验:GitLab对内存要求不低,至少4G。我曾在2G的服务器上跑,结果动不动就502。建议至少8G内存,否则你会很痛苦。

部署完成后,配置CI/CD流水线:

# .gitlab-ci.yml
stages:
  - build
  - test
  - deploy

build_job:
  stage: build
  script:
    - make clean
    - make all
  artifacts:
    paths:
      - build/*.bin

test_job:
  stage: test
  script:
    - qemu-system-arm -M vexpress-a9 -kernel build/zImage -dtb build/vexpress-v2p-ca9.dtb -drive file=build/rootfs.ext4,if=sd,format=raw -append "console=ttyAMA0 root=/dev/mmcblk0" -nographic -serial stdio

deploy_job:
  stage: deploy
  script:
    - scp build/*.bin user@target-board:/tmp/
  only:
    - main

这个流水线实现了:代码提交后自动编译、在QEMU中运行测试、通过后自动部署到目标板。说白了,这就是嵌入式DevOps的核心。

总结一下:环境搭建是基础,但也是最容易出问题的地方。交叉编译工具链选对版本、Buildroot配置精简、QEMU验证先行、GitLab自动化流水线。把这四步走稳了,后面的开发就会顺畅很多。

我记得第一次搭建完整环境时,光工具链就折腾了两天。现在有了这些经验,半小时就能搞定。所以别怕踩坑,每个坑都是成长的机会。