3. 开发环境准备:Linux操作系统、构建工具、依赖包安装

做 Android ARM 交叉编译,操作系统选对能省一半力气。我个人的习惯是直接用 Ubuntu,尤其 20.04 LTS 或 22.04 LTS,包管理最顺手,社区资源也多。你想想看,如果系统里缺个库,apt install 一行搞定,省下折腾时间好好写代码多好。

踩过的坑: 我曾经图新鲜拿 Fedora 36 做宿主,结果 NDK 自带的 sysroot 跟它的 glibc 版本打架,编译出来的 .so 在 target 设备上一运行就段错误。后来老老实实换回 Ubuntu 20.04,再也没出过这种玄学问题。所以,稳定比新潮重要。

3.1 安装基础构建工具

Linux 系统装完第一件事,把编译全家桶拉进来。别嫌多,后面缺哪个再补也来得及。

sudo apt update
sudo apt install build-essential cmake git curl wget \
                 autoconf automake libtool pkg-config \
                 ninja-build ccache

build-essential 包含了 gcc、g++、make 等核心工具,cmake 是主流构建系统,pkg-config 用来找依赖库的编译参数。嗯,这里要注意:如果你用 WSL2,记得先确认系统是 64 位,交叉编译工具链不认 32 位环境。

小技巧: 我在做 CI 时习惯把 ccache 装好,同一个源码反复编译时能节省 50% 以上时间。尤其交叉编译,本地执行一次,后面缓存命中率很高。

3.2 安装交叉编译工具链

Android 场景下,最正统的交叉编译器来自 NDK。我推荐直接下载官方 NDK 压缩包,别用系统包管理器里的过时版本。

# 以 NDK r25c (Linux 64-bit) 为例
wget https://dl.google.com/android/repository/android-ndk-r25c-linux.zip
unzip android-ndk-r25c-linux.zip
mv android-ndk-r25c ~/android-ndk-r25c

解压后,工具链藏在 toolchains/llvm/prebuilt/linux-x86_64/bin/ 里。你会发现名字都是 aarch64-linux-android21-clang 这种格式。数字 21 代表最低支持的 API Level。

为了避免每次敲路径,我把 NDK 路径加到 ~/.bashrc:

export ANDROID_NDK_HOME=$HOME/android-ndk-r25c
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH

然后 source ~/.bashrc 生效。验证一下:

$ aarch64-linux-android21-clang --version
clang version 14.0.6
Target: aarch64-linux-android21
Thread model: posix
注意: 千万不要用 root 用户执行编译。交叉编译时会创建临时目录、写缓存,root 权限容易把系统文件搞乱。我曾经手快 su 了之后编译,结果整个 /tmp 的权限全乱套,其他进程也跟着挂,教训深刻。

3.3 安装系统级依赖库

你写的 C/C++ 代码大概率会用到 zlib、OpenSSL、libpng、libusb 之类的库。这些库在宿主机上编译时,需要提供头文件和 .so。Android 编译时其实并不链接宿主机上的 .so,但头文件和 pkg-config 文件是需要的。

依赖库安装命令说明
zlibsudo apt install zlib1g-dev压缩库,几乎每个项目都用
OpenSSLsudo apt install libssl-dev加密和 HTTPS 支持
libpngsudo apt install libpng-dev图像处理,可选但常见
libusbsudo apt install libusb-1.0-0-devUSB 通信,驱动相关项目必装
expatsudo apt install libexpat1-devXML 解析,NDK 内部也依赖它

你可能会问:这些库安装后,交叉编译时怎么让编译器找到它们的头文件?其实很简单——标准路径 /usr/include 和 /usr/lib/x86_64-linux-gnu 里已经存好了宿主机的版本。但 Android 目标要用自己的 sysroot,所以建议把这些库的源码也下载一份,通过 CMake 的 find_package 机制配合工具链文件找。这部分我们后面会详细讲。

核心原则: 宿主机只提供头文件参考和编译依赖分析,真正的链接阶段必须用 NDK 提供的 sysroot 下的库文件。不要尝试把宿主机的 .so 直接扔给 Android 设备。

3.4 验证环境:写一个 Hello 交叉编译

光说不练假把式。我们写个最小的 C 程序,交叉编译成 Android 可执行文件,看看环境通不通。

先创建一个 hello.c:

#include <stdio.h>

int main() {
    printf("Hello from Android ARM! NDK version: %d\n", __ANDROID_API__);
    return 0;
}

用 aarch64 交叉编译器编译:

aarch64-linux-android21-clang -o hello_arm64 hello.c

如果没报错,你就能得到一个 hello_arm64 文件。用 file 命令看看类型:

$ file hello_arm64
hello_arm64: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /system/bin/linker64, not stripped

看到 ARM aarch64 就对了。把它 push 到 Android 设备上运行:

adb push hello_arm64 /data/local/tmp/
adb shell chmod +x /data/local/tmp/hello_arm64
adb shell /data/local/tmp/hello_arm64
# 输出:Hello from Android ARM! NDK version: 21
避坑指南: 如果你没有实体设备,可以用 Android 模拟器(x86_64 系统镜像也行,但测试时最好用 ARM 镜像)。另外,/data/local/tmp 是临时目录,重启后会被清空,别把重要东西放里面。

整个开发环境准备流程,我用一张图总结一下:

环境准备核心流程 Ubuntu 20.04 / 22.04 LTS build-essential · cmake · git NDK r25c → 设置 ANDROID_NDK_HOME LLVM + sysroot API Level ≥ 21 zlib · openssl · libpng 等 交叉编译 hello → adb 运行 关键:三者缺一不可,顺序不可颠倒