平台交叉编译名词解释与基础流程

1. 名词解释

1.1 NDK(Native Development Kit)

全称:Android Native Development Kit,Android 原生开发工具包。

作用 :提供一整套交叉编译工具链(编译器、链接器、头文件、标准库等),让你能在电脑上把 C/C++ 代码编译成 Android 手机上运行的 .so 库。

关键历史

  • NDK r18(2018 年):移除 GCC,Clang 成为唯一编译器
  • NDK r21(2020 年):停止支持 32 位 Windows
  • NDK r23(2021 年):首次支持 Mac Apple Silicon(M1/M2)通用二进制
  • NDK r24(2022 年):完整支持 Mac Apple Silicon
  • NDK r25+(2022 年至今):稳定支持所有主流平台

本项目使用的 NDK

  • 项目未显式指定 ndkVersion,Gradle 自动选择
  • Mac 本机已安装:21.1.6352462 / 23.1.7779620 / 24.0.8215888 / 28.2.13676358 / 30.0.14904198
  • 推荐统一指定版本:24.0.8215888(Mac M 系列 + Windows 均兼容)

1.2 CMake

是什么:一个跨平台的构建系统(构建工具)。

作用 :读取项目中的 CMakeLists.txt 配置文件,根据配置调度编译器来编译源码、链接库、生成最终产物。

类比

复制代码
CMake       = 施工指挥(读图纸,安排工序)
NDK 工具链  = 施工工具(编译器、链接器)
源码        = 建筑材料(.c/.cpp 文件)
.so 库      = 建好的房子(编译产物)

关键配置

cmake 复制代码
# CMakeLists.txt 第一行,声明所需的最低 CMake 版本
cmake_minimum_required(VERSION 3.10.2)
  • 如果本机 CMake 版本 ≥ 3.10.2 → 正常构建
  • 如果本机 CMake 版本 < 3.10.2 → 报错

Android Studio 内置 CMake 版本

Android Studio 版本 内置 CMake 说明
3.6 ~ 4.x 3.10.2 老项目常用
Arctic Fox+ 3.22.1 较新版本

版本兼容建议:NDK r21+ 配 CMake 3.10.2 没问题,NDK r25+ 建议配 CMake 3.22+。


1.3 Clang

是什么:C/C++/Objective-C 编译器前端,是 LLVM 编译器基础设施的一部分。

名字由来C + lang(language)→ C 语言编译器前端。虽然名字里有"C",但实际支持 C、C++、Objective-C、Objective-C++ 等多种语言。

完整翻译 :无官方中文译名,直接使用 Clang。可理解为 "LLVM 的 C 语言前端"(C Language Frontend for LLVM)。

编译流程

复制代码
C/C++ 源码
    ↓
Clang(编译器前端)→ 词法分析、语法分析、语义分析 → 生成 LLVM 中间代码(IR)
    ↓
LLVM(编译器后端)→ 优化 → 生成目标平台机器码(如 ARM64)
    ↓
产出 .so 库

与 NDK 的关系 :从 NDK r18 起,GCC 被移除,Clang 成为 NDK 唯一的编译器


1.4 LLVM

是什么:一个编译器基础设施项目,Clang 是它的前端。

分工

  • Clang(前端):负责把源码解析成中间代码 IR
  • LLVM(后端):负责优化 IR,生成目标平台的机器码

优势:前端和后端解耦,同一套前端可以支持多个目标平台(ARM、x86、RISC-V 等),同一套后端也可以接收不同语言的中间代码。


1.5 交叉编译(Cross Compilation)

定义:在 A 平台上编译出 B 平台运行的程序。

典型场景

复制代码
开发电脑(Mac x86_64 / ARM64)
    ↓ 交叉编译
Android 手机(ARM64)上运行的 .so 库

为什么需要交叉编译

  • 手机上没有编译环境(没有编译器、构建工具等)
  • 手机性能不足,不适合编译
  • 所以在电脑上编译好,把结果(.so)打包进 APK,再部署到手机运行

对比

类型 编译器运行平台 产物运行平台 举例
本地编译 Mac Mac Mac 上跑的 .app
交叉编译 Mac Android Android 上跑的 .so

NDK 就是 Android 的交叉编译工具包------提供运行在 Mac/Windows/Linux 上、但产出 Android 平台二进制的编译器(Clang)和工具链。


1.6 ABI(Application Binary Interface)

是什么:应用程序二进制接口,定义了二进制代码在特定 CPU 架构上运行的规范。

Android 支持的 ABI

ABI CPU 架构 说明
armeabi-v7a ARM 32 位 老设备,主流兼容
arm64-v8a ARM 64 位 现代手机主流
x86 Intel/AMD 32 位 模拟器
x86_64 Intel/AMD 64 位 模拟器

与交叉编译的关系:交叉编译时需要指定目标 ABI,Clang 会根据 ABI 生成对应架构的机器码。


1.7 .so 文件(Shared Library)

是什么:共享库(动态链接库),C/C++ 编译后的最终产物。

在 Android 中的位置 :打包进 APK 的 lib/<abi>/ 目录下:

复制代码
APK
└── lib/
    ├── armeabi-v7a/
    │   └── libxxx.so
    ├── arm64-v8a/
    │   └── libxxx.so
    └── x86_64/
        └── libxxx.so

加载方式 :Java 层通过 System.loadLibrary("xxx") 加载(不带 lib 前缀和 .so 后缀)。


1.8 JNI(Java Native Interface)

是什么:Java 原生接口,Java 与 C/C++ 之间的桥梁。

作用 :让 Java 代码能调用 C/C++ 编写的 .so 库中的函数,反之亦然。

流程

复制代码
Java 代码  →  JNI  →  C/C++ 函数(.so 库中)
    ↑                        |
    └──── 返回值 ←───────────┘

1.9 Gradle externalNativeBuild

是什么:Gradle 的一个配置块,用于将 C/C++ 的原生代码构建集成到 Android 的 Gradle 构建流程中。

配置示例

groovy 复制代码
android {
    defaultConfig {
        externalNativeBuild {
            cmake {
                cppFlags "-std=c++14"
                abiFilters 'armeabi-v7a', 'arm64-v8a'
            }
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
        }
    }
}

作用 :告诉 Gradle 去哪找 CMakeLists.txt,以及编译哪些 ABI、用什么 C++ 标准等。


2. 基础流程

2.1 整体编译流程图

复制代码
┌─────────────────────────────────────────────────────────────┐
│                        开发者编写代码                         │
│  Java/Kotlin (.java/.kt)          C/C++ (.c/.cpp)           │
│         │                              │                     │
│         │                    CMakeLists.txt (构建配置)       │
│         │                              │                     │
└─────────┼──────────────────────────────┼─────────────────────┘
          │                              │
          │                    ┌─────────┘
          │                    │
          │              Gradle externalNativeBuild
          │                    │
          │                    ▼
          │              CMake 读取 CMakeLists.txt
          │              (配置源文件、编译选项、目标 ABI 等)
          │                    │
          │                    ▼
          │              调用 NDK 工具链中的 Clang
          │              (交叉编译:Mac/Win 上编译,产出 Android .so)
          │                    │
          │              ┌─────┴──────┐
          │              │ Clang 前端   │  词法/语法分析 → IR
          │              │ LLVM 后端    │  优化 → 机器码
          │              └─────────────┘
          │                    │
          │                    ▼
          │              生成 .so 库
          │              lib/armeabi-v7a/libxxx.so
          │              lib/arm64-v8a/libxxx.so
          │              lib/x86_64/libxxx.so
          │                    │
          │                    ▼
          │           Gradle 将 .so 打包进 APK
          │                    │
          ▼                    ▼
┌──────────────────────────────────────────┐
│                 APK 文件                 │
│  ├── classes.dex (Java/Kotlin 编译产物)  │
│  ├── lib/                               │
│  │   ├── arm64-v8a/libxxx.so            │
│  │   └── armeabi-v7a/libxxx.so          │
│  └── res/                               │
└──────────────────────────────────────────┘
                    │
                    ▼
┌──────────────────────────────────────────┐
│           Android 手机运行时              │
│                                          │
│  Java 代码                                │
│    ↓ System.loadLibrary("xxx")          │
│  JNI 桥梁                                 │
│    ↓ 调用                                │
│  C/C++ 函数(.so 库中)                   │
└──────────────────────────────────────────┘

2.2 各工具协作关系

复制代码
工具/技术        角色              作用
──────────────────────────────────────────────────────
CMakeLists.txt  配置文件           声明源文件、编译选项、输出库名等
CMake           构建系统           读取配置,调度编译过程
NDK             工具链包           提供交叉编译所需的编译器、头文件、标准库
Clang           编译器前端         把 C/C++ 源码解析成中间代码 IR
LLVM            编译器后端         优化 IR,生成目标平台机器码
Gradle          构建管理           管理整体构建流程,把 .so 打包进 APK
JNI             桥梁协议           Java 与 C/C++ 互调的接口规范
.so             产物              编译产出的共享库,打包进 APK 运行

2.3 编译执行顺序

复制代码
1. Gradle 开始构建
2. Gradle 读取 externalNativeBuild 配置,找到 CMakeLists.txt
3. CMake 解析 CMakeLists.txt,生成构建脚本(ninja/Makefile)
4. 构建脚本调用 NDK 中的 Clang 编译器
5. Clang 前端:源码 → 词法分析 → 语法分析 → 语义分析 → 生成 IR
6. LLVM 后端:优化 IR → 生成目标 ABI 的机器码
7. 链接器(lld):把多个目标文件链接成 .so 库
8. Gradle 把 .so 库打包进 APK 的 lib/<abi>/ 目录
9. APK 安装到手机后,Java 通过 JNI 调用 .so 中的函数

3. 本项目相关配置

3.1 构建工具版本

配置项 配置位置
AGP 4.1.3 build.gradle
NDK 未显式指定(Gradle 自动选择) app/build.gradle(注释了 ndkVersion '24.0.7856742 rc1'
CMake 未显式指定(使用 Android Studio 内置) CMakeLists.txtcmake_minimum_required(VERSION 3.10.2)

3.2 多设备统一建议

核心建议:在 app/build.gradle 中显式指定 ndkVersion "24.0.8215888",确保 Mac M 系列和 Windows 均兼容且编译产物一致。

相关推荐
__Witheart__2 小时前
3568 Android otg模式下adb热拔插不识别
android·adb·rockchip
明天…ling4 小时前
Upload-Labs (Pass1-Pass21) 完整通关思路与源码分析
android·网络安全·渗透测试·burpsuite·upload-labs·文件上传绕过·靶场复现
__Witheart__4 小时前
3568 Android ntp校时使用
android·rockchip
wddptwd285 小时前
android studio 报错怎么处理 java.lang.NullPointerException
android·java·android studio
美狐美颜SDK开放平台5 小时前
直播APP开发,美颜SDK和相机SDK有什么区别?
android·深度学习·数码相机·ios·直播美颜sdk·视频美颜sdk
唐诺6 小时前
Android Open Accessory (AOA) 协议完全解析
android·usb·aoa
我命由我123458 小时前
Android 开发 - 广播组件(标准广播、有序广播、静态注册广播、分钟到达广播、网络变更广播...)
android·java·开发语言·网络·java-ee·android studio·android-studio
A富得流油的咸鸭蛋8 小时前
安卓鸿蒙面试
android·面试·harmonyos
wardenlzr8 小时前
@IntDef 替代 enum:Android 官方推荐的轻量常量方案
android·性能