Android NDK 编译 protobuf

最近收到一个小伙伴的私信,Android平台帮忙编译一个Native C++项目,这个项目中用到了Protobuf 和OpenCV两个C++库,其中OpenCV有现成的动态库.so了,但是Protobuf并没有现成的,需要自己拿源码编译!废话不多说,直接上干货...

首先,准备编译所需要的工具

在 macOS M4(ARM 架构)上为 Android 交叉编译 Protobuf (如v3.19.6版本)的 .so 动态库,需要使用 Android NDK 配置交叉编译环境,针对不同的 Android CPU 架构(如 arm64-v8a、armeabi-v7a、x86_64 等)生成对应版本的库。

  1. 安装依赖工具

    确保已安装基础编译工具cmake 和版本控制工具git,使用brew安装即可。

  2. 下载 Android NDK

    交叉编译 Android 库需要 NDK 提供的工具链,可以直接去官网下载, 也可以在Android Studio的SDK Manager中下载。下载完成解压到指定目录,这个目录我们称为NDK_PATH,也可以将它配置环境变量中

  3. 下载 Protobuf 3.19.6 源码

bash 复制代码
    git clone https://github.com/protocolbuffers/protobuf.git
    cd protobuf
    git checkout v3.19.6
    git submodule update --init --recursive  # 拉取子模块(如 googletest)

接着,交叉编译 Protobuf 到 Android .so(核心步骤)

Protobuf 支持 CMake 交叉编译,需为每个目标架构(如 arm64-v8a、armeabi-v7a)单独配置编译参数。

1. 定义编译参数(通用配置

先设置通用变量,方便后续复用:

bash 复制代码
    # NDK 路径(替换为你的实际路径)
    export NDK_PATH=/Users/xxx/Library/Android/sdk/ndk/26.1.10909125

    # Protobuf 源码根目录(当前目录)
    export PROTOBUF_SRC=$(pwd)

    # 输出目录(所有架构的 .so 最终会放到这里)
    export OUTPUT_DIR=$(pwd)/android_build
    mkdir -p $OUTPUT_DIR

2. 针对不同架构编译(以 arm64-v8a 为例)

Android 主流架构包括: arm64-v8a(64 位 ARM,主流新设备) armeabi-v7a(32 位 ARM,老旧设备) x86_64(64 位 x86,模拟器常用) 以下以 arm64-v8a 为例,其他架构仅需修改对应参数即可。

步骤 1:设置当前架构的参数

ini 复制代码
    # 目标架构(根据需要替换为 armeabi-v7a、x86_64 等)
    TARGET_ARCH=arm64-v8a

    # NDK 对应的工具链架构(arm64-v8a 对应 aarch64,armeabi-v7a 对应 arm,x86_64 对应 x86_64)
    TOOLCHAIN_ARCH=aarch64

    # Android 最小支持版本(根据需求修改,如 21 及以上支持 64 位)
    MIN_SDK_VERSION=21

    # 构建目录(每个架构单独一个目录,避免冲突)
    BUILD_DIR=$(pwd)/build_$TARGET_ARCH
    mkdir -p $BUILD_DIR
    cd $BUILD_DIR

步骤 2:生成 CMake 交叉编译配置

使用 NDK 提供的 build/cmake/android.toolchain.cmake 工具链文件,指定交叉编译参数:

ini 复制代码
    cmake \
      -DCMAKE_SYSTEM_NAME=Android \  # 目标系统为 Android
      -DCMAKE_SYSTEM_VERSION=$MIN_SDK_VERSION \  # 最小 SDK 版本
      -DCMAKE_ANDROID_ARCH_ABI=$TARGET_ARCH \  # 目标 ABI
      -DCMAKE_ANDROID_NDK=$NDK_PATH \  # NDK 路径
      -DCMAKE_ANDROID_STL_TYPE=c++_shared \  # 使用 C++ 共享库(需与应用一致)
      -DCMAKE_BUILD_TYPE=Release \  #  Release 模式(优化编译)
      -DCMAKE_INSTALL_PREFIX=$OUTPUT_DIR/$TARGET_ARCH \  # 安装路径(按架构区分)
      -DBUILD_SHARED_LIBS=ON \  # 编译动态库(.so)
      -DBUILD_STATIC_LIBS=OFF \  # 不需要静态库
      -Dprotobuf_BUILD_TESTS=OFF \  # 禁用测试(加速编译)
      -Dprotobuf_BUILD_EXAMPLES=OFF \  # 禁用示例
      $PROTOBUF_SRC/cmake  # cmakelist.txt 所在目录
      

步骤 3:编译并安装

bash 复制代码
    # 编译(-j 后面的数字为并行线程数,根据 CPU 核心数调整,如 8)
    make -j8

    # 安装到指定的输出目录($OUTPUT_DIR/$TARGET_ARCH)
    make install

编译完成后,OUTPUT_DIR/TARGET_ARCH/lib*** 目录下会生成 libprotobuf.so 和 libprotobuf-lite.so(轻量版)。

3. 编译其他架构

替换 TARGET_ARCH 和 TOOLCHAIN_ARCH 重复上述步骤即可:

armeabi-v7a:

ini 复制代码
    TARGET_ARCH=armeabi-v7a
    TOOLCHAIN_ARCH=arm
    MIN_SDK_VERSION=16  # 32 位最低支持 16

x86_64:

ini 复制代码
    TARGET_ARCH=x86_64
    TOOLCHAIN_ARCH=x86_64
    MIN_SDK_VERSION=21

最后,将以上步骤写成一个脚本文件,只需要在一个空文件夹下执行脚本即可。

protobuf_android.sh

bash 复制代码
#!/bin/bash

# 配置参数(请根据实际环境修改)
NDK_PATH="/Users/xxx/Library/Android/sdk/ndk/26.1.10909125" # Android NDK 路径
PROTOBUF_VERSION="v3.19.6"         # Protobuf 版本
OUTPUT_ROOT="$PWD/protobuf-android-build"  # 输出目录根路径
MIN_SDK_ARM64=21                   # arm64-v8a 最小支持 SDK 版本
MIN_SDK_ARM32=21                   # armeabi-v7a 最小支持 SDK 版本
MIN_SDK_X86=21                     # x86_64 最小支持 SDK 版本
THREADS=4                          # 并行编译线程数(根据 CPU 核心数调整)

# 检查 NDK 是否存在
if [ ! -d "$NDK_PATH" ]; then
    echo "错误:NDK 路径不存在,请检查 NDK_PATH 配置"
    exit 1
fi

# 检查依赖工具
check_dependency() {
    if ! command -v $1 &> /dev/null; then
        echo "错误:未找到 $1,请先安装(可通过 brew install $1)"
        exit 1
    fi
}
check_dependency "git"
check_dependency "cmake"
check_dependency "make"

# 添加vpn终端代理命令,加速从github上下载代码
#export https_proxy=http://xxx:端口 http_proxy=http://xxx:端口 all_proxy=socks5://xxx:端口

# 克隆并准备 Protobuf 源码
echo "===== 下载 Protobuf $PROTOBUF_VERSION 源码 ====="
if [ ! -d "protobuf" ]; then
    git clone https://github.com/protocolbuffers/protobuf.git || exit 1
fi
cd protobuf || exit 1
git checkout $PROTOBUF_VERSION || exit 1
git submodule update --init --recursive || exit 1
PROTOBUF_SRC=$(pwd)
cd .. || exit 1

# 创建输出目录
mkdir -p "$OUTPUT_ROOT"

# 交叉编译函数(参数:目标架构 工具链架构 最小 SDK 版本)
build_arch() {
    local TARGET_ARCH=$1
    local TOOLCHAIN_ARCH=$2
    local MIN_SDK=$3
    local BUILD_DIR="$PWD/build_$TARGET_ARCH"
    local INSTALL_DIR="$OUTPUT_ROOT/$TARGET_ARCH"

    echo -e "\n===== 开始编译 $TARGET_ARCH 架构 ====="
    echo "构建目录: $BUILD_DIR"
    echo "安装目录: $INSTALL_DIR"

    # 创建并进入构建目录
    mkdir -p "$BUILD_DIR" && cd "$BUILD_DIR" || exit 1

    # 运行 CMake 配置
    cmake \
        -DCMAKE_SYSTEM_NAME=Android \
        -DCMAKE_SYSTEM_VERSION=$MIN_SDK \
        -DCMAKE_ANDROID_ARCH_ABI=$TARGET_ARCH \
        -DCMAKE_ANDROID_NDK=$NDK_PATH \
        -DCMAKE_ANDROID_STL_TYPE=c++_shared \
        -DCMAKE_BUILD_TYPE=Release \
        -DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" \
        -DBUILD_SHARED_LIBS=ON \
        -DBUILD_STATIC_LIBS=OFF \
        -Dprotobuf_BUILD_TESTS=OFF \
        -Dprotobuf_BUILD_EXAMPLES=OFF \
        "$PROTOBUF_SRC/cmake" || {
        echo "CMake 配置 $TARGET_ARCH 失败"
        exit 1
    }

    # 编译并安装
    make -j$THREADS || {
        echo "编译 $TARGET_ARCH 失败"
        exit 1
    }
    make install || {
        echo "安装 $TARGET_ARCH 失败"
        exit 1
    }

    # 返回上层目录
    cd .. || exit 1
    echo "===== $TARGET_ARCH 编译完成 ====="
}

# 编译各架构(按需求注释不需要的架构)
build_arch "arm64-v8a" "aarch64" $MIN_SDK_ARM64
build_arch "armeabi-v7a" "arm" $MIN_SDK_ARM32
build_arch "x86_64" "x86_64" $MIN_SDK_X86

echo -e "\n===== 所有架构编译完成 ====="
echo "输出目录: $OUTPUT_ROOT"
echo "各架构 .so 文件路径:"
find "$OUTPUT_ROOT" -name "libprotobuf.so"
相关推荐
晚风叙码6 小时前
MySQL 数据类型详解:从数值到字符串,一篇讲透
android·mysql·adb
传奇开心果编程7 小时前
【Compose Multiplatform 跨端开发学与练】第3课 布局与组件
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程10 小时前
【Compose Multiplatform 跨端开发学与练】第8课 资源管理与主题
android·windows·学习·ios·kotlin·web·composer
传奇开心果编程11 小时前
【Compose Multiplatform 跨端开发学与练】第9课 测试与调试
android·学习·macos·ios·kotlin·web·composer
传奇开心果编程11 小时前
【Compose Multiplatform 跨端开发学与练】第4课 导航与路由
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程12 小时前
【Compose Multiplatform 跨端开发学与练】第6课 状态管理与架构
android·学习·ui·ios·架构·kotlin·composer
事圆则缓12 小时前
Android AOSP 定制常见概念:源码目录、系统镜像与刷机流程
android
传奇开心果编程12 小时前
【Compose Multiplatform 跨端开发学与练】第2课 Compose 基础语法
android·windows·学习·ui·ios·kotlin·composer
supabc12312 小时前
Celium:连接 Windows、Mac、Linux 与 Android,让远程访问和设备管理更简单
android·linux·windows·macos·远程访问·网络管理·celium
Dovis(誓平步青云)13 小时前
导览音频切换太快,旧讲解不能覆盖新展品
android·前端·javascript·ecmascript·音视频·宠物