第2章:交叉编译环境搭建

说实话,很多做嵌入式Linux的朋友,第一步就栽在环境搭建上。不是工具链装不上,就是路径配不对,折腾半天连个Hello World都跑不起来。我当年刚入行时也踩过这个坑,花了整整一个下午才发现是环境变量写错了。

这一章,咱们就把交叉编译环境彻底搞定。你跟着我的步骤来,保证一次过。

2.1 什么是交叉编译?为什么需要它?

先搞清楚一个概念。你平时在PC上写代码,编译出来的程序是给x86架构用的。但ARM开发板是ARM架构,指令集完全不同。你不能在x86上直接编译ARM程序——除非用交叉编译。

交叉编译,说白了就是:
在A架构的机器上,编译出能在B架构上运行的程序。

我们现在的场景是:
宿主机(Host):你的PC,x86架构,Ubuntu系统
目标机(Target):ARM开发板,ARM架构,Linux系统

核心要点:交叉编译工具链里包含了针对ARM架构的编译器、链接器、库文件。它知道怎么生成ARM的机器码,而不是x86的。

交叉编译流程示意图 宿主机(x86) gcc-arm-linux-gnueabihf 编译 + 链接 生成 ARM 可执行文件 ELF格式,ARM指令集 拷贝/下载 目标机 ARM 关键区别 本地编译:x86 → x86 | 交叉编译:x86 → ARM

2.2 安装交叉编译工具链

我们选用的是 gcc-arm-linux-gnueabihf。这个工具链支持硬件浮点运算(hf = hard float),性能更好。如果你的ARM芯片支持硬件浮点(现在基本都支持),就用这个。

安装方式有两种,我推荐第一种:

方式一:apt 直接安装(推荐)

sudo apt update
sudo apt install gcc-arm-linux-gnueabihf

装完之后,验证一下:

arm-linux-gnueabihf-gcc --version

你应该能看到类似这样的输出:

arm-linux-gnueabihf-gcc (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0
Copyright (C) 2017 Free Software Foundation, Inc.

我的建议:用apt安装最省心。版本可能不是最新的,但稳定。我在项目中一直用7.5.0,从来没出过兼容性问题。

方式二:从Linaro官网下载(进阶)

如果你需要特定版本,可以去Linaro官网下载。步骤稍多:

  1. 下载工具链压缩包(例如 gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz)
  2. 解压到 /opt 目录
  3. 手动配置环境变量
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

注意:下载链接可能会变。建议直接去Linaro官网找最新稳定版。我曾经因为用了过期的链接,折腾了半天才发现是404。

2.3 配置环境变量

工具链装好了,但系统还不知道它在哪。你需要把它的路径加到 PATH 里。

我个人习惯把配置写在 ~/.bashrc 里,这样每次打开终端都自动生效。

echo 'export PATH=$PATH:/usr/bin/arm-linux-gnueabihf-' >> ~/.bashrc
source ~/.bashrc

如果你用的是方式二(手动解压到 /opt),路径要改成:

echo 'export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin' >> ~/.bashrc
source ~/.bashrc

验证一下:

which arm-linux-gnueabihf-gcc

如果返回了路径,说明配置成功。

小技巧:你可以用 echo $PATH 查看当前所有路径。如果发现工具链路径没在里面,八成是写错了或者没source。

2.4 编写第一个交叉编译程序:Hello World

环境搭好了,来写个程序验证一下。老规矩,Hello World。

步骤1:写源码

mkdir -p ~/arm_hello
cd ~/arm_hello
vim hello.c

写入以下内容:

#include <stdio.h>

int main()
{
    printf("Hello, ARM Linux!\n");
    printf("This is my first cross-compiled program.\n");
    return 0;
}

步骤2:交叉编译

arm-linux-gnueabihf-gcc hello.c -o hello_arm

编译完成后,用 file 命令看看生成的文件:

file hello_arm

你应该看到类似这样的输出:

hello_arm: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, not stripped

看到 ARM 两个字了吗?这说明它确实是ARM架构的可执行文件。

验证要点:如果你在x86的PC上直接运行 ./hello_arm,会报错 Exec format error。这是正常的!因为你的CPU不认识ARM指令。这个程序只能拿到ARM开发板上跑。

步骤3:在ARM开发板上运行

把 hello_arm 拷贝到开发板上。方法很多:

  • 通过 scp 网络传输
  • 通过U盘拷贝
  • 通过串口传输(慢,不推荐)

假设你的开发板IP是 192.168.1.100,用户名是 root:

scp hello_arm root@192.168.1.100:/root/

然后在开发板上执行:

chmod +x hello_arm
./hello_arm

如果看到:

Hello, ARM Linux!
This is my first cross-compiled program.

恭喜你,交叉编译环境搭建成功!

2.5 常见问题与避坑指南

问题 原因 解决方法
command not found 环境变量没配好 检查 PATH,重新 source ~/.bashrc
Exec format error 在x86上直接运行ARM程序 这是正常的,拷贝到开发板上运行
cannot execute binary file 架构不匹配或权限不足 检查 file 输出,确认是ARM;加 chmod +x
编译时提示缺少头文件 工具链安装不完整 重新安装 gcc-arm-linux-gnueabihf

我曾经踩过的坑:有一次我编译出来的程序在开发板上跑不起来,提示 Segmentation fault。查了半天,发现是工具链版本和开发板上的glibc版本不匹配。解决办法:要么升级开发板的glibc,要么用更老版本的工具链。从那以后,我每次都会先确认开发板的glibc版本,再选工具链。

2.6 本章小结

这一章我们做了三件事:

  • 安装了交叉编译工具链 gcc-arm-linux-gnueabihf
  • 配置了环境变量,让系统能找到它
  • 编写并验证了第一个交叉编译的Hello World程序

现在你的开发环境已经就绪。接下来的章节,我们会在这个基础上,一步步深入ARM驱动的世界。