3、交叉编译环境搭建:交叉编译工具链安装、环境变量配置、验证工具链
好,咱们进入第三章。说实话,交叉编译环境搭建这事儿,看着简单,但我在项目里见过太多人在这上面栽跟头了。你想想看,车载中控的芯片通常是ARM架构,而你的开发电脑是x86架构,这两者之间怎么通信?靠的就是交叉编译工具链。
说白了,交叉编译就是「在A平台上生成B平台能跑的程序」。嗯,这个概念一定要刻在脑子里。
3.1 交叉编译工具链的安装
我个人习惯用Linaro提供的工具链,稳定、社区活跃。当然,如果你用的是NXP i.MX系列或者瑞萨R-Car系列,芯片原厂也会提供定制版工具链。但不管哪种,安装思路是一样的。
先说说最常见的安装方式——下载预编译包。
# 以ARM Cortex-A7为例,下载gcc-arm-linux-gnueabihf
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/
# 进入目录看看
cd /opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf
ls -l bin/
解压完后,你会看到bin目录下有一堆以arm-linux-gnueabihf-开头的文件。这就是工具链的核心——编译器、链接器、汇编器等等。
重要: 工具链版本要和内核版本匹配。比如Linux 4.14内核,用gcc 7.x系列就挺好。版本差太多,编译时会出现各种奇奇怪怪的语法错误。
我记得有一次,项目组新来的同事用gcc 10.x去编译Linux 4.9内核,结果报了一堆implicit declaration错误。折腾了两天才发现是工具链太新,内核代码里有些旧语法不兼容了。
3.2 环境变量配置
工具链装好了,但系统还不知道它在哪。这时候就需要配置环境变量了。
我个人习惯把配置写在~/.bashrc里,这样每次打开终端自动生效。当然,你也可以写在/etc/profile里,但那是全局的,不太推荐。
# 编辑 ~/.bashrc
vim ~/.bashrc
# 在文件末尾添加以下内容
export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin
export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm
# 保存退出后,使配置生效
source ~/.bashrc
这里解释一下三个变量的作用:
| 变量名 | 作用 | 示例值 |
|---|---|---|
| PATH | 告诉系统去哪找可执行文件 | /opt/.../bin |
| CROSS_COMPILE | 指定交叉编译器的前缀 | arm-linux-gnueabihf- |
| ARCH | 指定目标架构 | arm |
小技巧: 如果你同时维护多个项目,每个项目用的工具链版本不同,我建议你在每个项目的Makefile里单独指定这些变量,而不是写在全局环境里。这样切换项目时不会互相干扰。
你可能会问:为什么CROSS_COMPILE后面要加个短横线?嗯,这是因为工具链里的所有命令都是以arm-linux-gnueabihf-开头的,比如arm-linux-gnueabihf-gcc、arm-linux-gnueabihf-ld。加上短横线,Makefile里就能自动补全了。
3.3 验证工具链
配置完了,怎么知道好不好使?别急,三步验证法,我一直在用。
第一步:检查命令是否可找到
which arm-linux-gnueabihf-gcc
如果返回了路径,说明PATH配置没问题。如果返回no ... in,那就是PATH没加对,回去检查一下。
第二步:查看编译器版本
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.
This is free software; see the source for copying conditions.
版本号出来了,说明编译器本身能正常工作。
第三步:编译一个测试程序
写一个最简单的C程序:
// hello.c
#include <stdio.h>
int main(void)
{
printf("Hello, ARM Linux!\n");
return 0;
}
然后用交叉编译器编译:
arm-linux-gnueabihf-gcc -o hello hello.c
编译完成后,用file命令看看生成的文件:
file hello
如果输出是:
hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3
恭喜你,交叉编译环境搭建成功了!这个文件是ARM架构的,在x86电脑上跑不了,得放到开发板上才能执行。
注意: 如果你在x86电脑上直接运行./hello,会报错cannot execute binary file: Exec format error。这是正常的,别慌。我见过有人以为工具链坏了,折腾半天才发现是在本地运行了ARM程序。
3.4 常见问题与避坑指南
最后,分享几个我在项目中踩过的坑:
- 权限问题: 工具链解压到
/opt后,普通用户可能没有执行权限。记得chmod +x一下,或者用sudo执行。 - 32位库缺失: 有些工具链是32位的,在64位系统上需要安装32位兼容库。命令是
sudo apt install lib32z1 lib32ncurses5。 - 路径中有中文或空格: 千万别把工具链放在带中文或空格的目录下,Makefile解析时会出问题。我曾经吃过这个亏,项目目录叫「项目_v2.0」,结果编译时各种路径错误。
- 多版本冲突: 如果你装了多个工具链,注意PATH里的顺序。系统会使用第一个找到的。我建议用
update-alternatives来管理。
好了,交叉编译环境搭建就讲到这里。下一章咱们开始真正的内核裁剪,到时候你会频繁用到这个工具链。确保它工作正常,不然后面全是白费功夫。