将 NDK 与其他构建系统结合使用

NDK 包含对 ndk-buildCMake 的官方支持。大多数用户应参考这些指南之一来构建应用代码。本文档的目的是介绍如何构建使用其他构建系统的现有代码。第三方依赖项通常属于这种情况,这些依赖项不是 Android 特有的,例如 OpenSSL 和 libbzip2。

希望向其构建系统添加原生 NDK 支持的构建系统维护者应改为阅读构建系统维护者指南

概览

NDK 中的 Clang 编译器可以使用,只需少量配置即可定义您的目标环境。

为了确保您为正确的架构构建,请在调用 Clang 时使用 -target 传递适当的目标。例如,要为 minSdkVersion 为 21 的 64 位 ARM Android 编译,请执行以下操作

$ $NDK/toolchains/llvm/prebuilt/$HOST_TAG/bin/clang++ \
    --target=aarch64-linux-android21 foo.cpp

或者,Clang 有目标前缀的入口点。根据 NDK 版本和主机操作系统,这些入口点可以是符号链接或转发到 Clang 的脚本。直接使用 --target 调用 Clang 将更可靠,因为这是经过最多测试的工作流程,而且脚本中偶尔会出现参数转发 bug。在 Windows 上,从脚本转发到真实编译器所需的额外 CreateProcess 可能会对构建速度产生明显的负面影响。

$ $NDK/toolchains/llvm/prebuilt/$HOST_TAG/bin/aarch64-linux-android21-clang++ \
    foo.cpp

在这两种情况下,请将 $NDK 替换为 NDK 的路径,并将 $HOST_TAG 替换为与您根据下表下载的 NDK 相匹配的主机标签

NDK 操作系统变体 主机标签
macOS darwin-x86_64
Linux linux-x86_64
64 位 Windows windows-x86_64

此处前缀或目标参数的格式是目标三元组,带有表示 minSdkVersion 的后缀。此后缀仅用于 clang/clang++;binutils 工具(如 arstrip)不需要后缀,因为它们不受 minSdkVersion 的影响。Android 支持的目标三元组如下

ABI 三元组
armeabi-v7a armv7a-linux-androideabi
arm64-v8a aarch64-linux-android
x86 i686-linux-android
x86-64 x86_64-linux-android

许多项目的构建脚本会期望 GCC 风格的交叉编译器,其中每个编译器只针对一种操作系统/架构组合,因此可能无法干净地处理 -target。在这种情况下,您通常可以将 -target 参数包含在编译器定义中(例如 CC="clang -target aarch64-linux-android21)。在您使用的构建系统无法使用该形式的极少数情况下,请使用带有三元组前缀的 Clang 二进制文件。

Autoconf

Autoconf 项目允许您使用环境变量指定要使用的工具链。例如,以下示例展示了如何在 Linux 上构建 minSdkVersion 为 API 级别 21 的 Android x86-64 版 libpng

# Check out the source.
git clone https://github.com/glennrp/libpng -b v1.6.37
cd libpng
# Only choose one of these, depending on your build machine...
export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64
# Only choose one of these, depending on your device...
export TARGET=aarch64-linux-android
export TARGET=armv7a-linux-androideabi
export TARGET=i686-linux-android
export TARGET=x86_64-linux-android
# Set this to your minSdkVersion.
export API=21
# Configure and build.
export AR=$TOOLCHAIN/bin/llvm-ar
export CC="$TOOLCHAIN/bin/clang --target=$TARGET$API"
export AS=$CC
export CXX="$TOOLCHAIN/bin/clang++ --target=$TARGET$API"
export LD=$TOOLCHAIN/bin/ld
export RANLIB=$TOOLCHAIN/bin/llvm-ranlib
export STRIP=$TOOLCHAIN/bin/llvm-strip
./configure --host $TARGET
make

此示例中选择的工具适用于 NDK r22 及更高版本。旧版 NDK 可能需要不同的工具。

非 autoconf make 项目

某些 makefile 项目允许通过覆盖与 autoconf 项目相同的变量来进行交叉编译。例如,以下示例展示了如何构建 minSdkVersion 为 21 的 Android x86-64 版 libbzip2

# Check out the source.
git clone https://gitlab.com/bzip/bzip2.git
cd bzip2

# Only choose one of these, depending on your build machine...
export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64

# Only choose one of these, depending on your device...
export TARGET=aarch64-linux-android
export TARGET=armv7a-linux-androideabi
export TARGET=i686-linux-android
export TARGET=x86_64-linux-android

# Set this to your minSdkVersion.
export API=21

# Build.
make \
    CC="$TOOLCHAIN/bin/clang --target=$TARGET$API" \
    AR=$TOOLCHAIN/bin/llvm-ar \
    RANLIB=$TOOLCHAIN/bin/llvm-ranlib \
    bzip2

此示例中选择的工具适用于 NDK r22 及更高版本。旧版 NDK 可能需要不同的工具。