编译 Android so库和可运行二进制文件的方式有两种:

  • ndk-build
  • cmake

ndk-build 只能编译 Android 平台运行的 so 库或者可执行的二进制文件,cmake 支持跨平台的交叉编译

ndk-build

这种方式需要 Android.mkApplication.mk 文件配合编译,通过一个 demo 了解利用 ndk-build 的整个过程,首先一段很简单的 C 代码:

1
2
3
4
5
6
#include <stdio.h>

int main(){
printf("hello world\n");
return 0;
}

Android.mk 文件配置:

1
2
3
4
5
6
7
8
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ndk_build_demo
LOCAL_SRC_FILES := main.c
# BUILD_SHARED_LIBRARY 编译结果为 .so 文件
include $(BUILD_SHARED_LIBRARY)
# BUILD_EXECUTABLE 编译结果为可执行二进制文件
# include $(BUILD_EXECUTABLE)

Application.mk 文件配置:

1
2
APP_PLATFORM := android-16
APP_BUILD_SCRIPT := Android.mk

配置完成后,运行命令 ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk NDK_APPLICATION_MK=./Application.mk

运行完成生成 libsobj 两个文件夹,其中 libs 文件夹中存放着对应各个 CPU 架构的 .so 文件

cmake

cmake 的编译方式需要有 CMakeLists.txt 文件配合编译,通过编译一个可在 Android 平台运行的二进制文件为例简单了解一下整个编译过程,其中 C 文件不变,以下是 CMakeLists.txt 的配置:

1
2
3
4
5
6
7
8
cmake_minimum_required(VERSION 3.8.2)
set(CMAKE_TOOLCHAIN_FILE ndk-path/build/cmake/android.toolchain.cmake)
project(demo)
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_VERSION 21) # API level
set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)

add_executable(run main.c)
  • CMAKE_TOOLCHAIN_FILE - 将提前加载指定的文件中的设置项设置编译器的值

其他的配置查阅cmake 文档

配置完成后,执行命令:

1
2
$ cmake .
$ make

编译结果:

其中需要注意Check for working C compilerCheck for working CXX compiler的内容,只有使用 NDK 中的编译器才能正确编译出在 Android 平台运行的 .so 和可执行二进制文件

这种把跟平台相关的配置写入 CMakeLists.txt 的写法其实不太好,让 CMakeLists.txt 文件看起来很臃肿,CMakeLists.txt 文件中应该只存放编译源码相关的配置,和平台相关的配置最好单独放到对应平台的 shell 脚本中:

1
2
3
4
5
6
#!/usr/bin/env bash
cmake -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK}/build/cmake/android.toolchain.cmake" \
-DCMAKE_BUILD_TYPE=Debug \
-DANDROID_ABI="armeabi-v7a" \
-DANDROID_PLATFORM="android-21" \
.

Clion 配置

Clion 默认查找本机环境的头文件,在开发 Android 驱动或者 NDK 开发时默认无法找到 NDK 包含的头文件,需要在 CMakeLists.txt 当中配置 CMAKE_C_COMPILERCMAKE_CXX_COMPILER 这两个编译器的属性,以及指定 NDK 头文件根目录:

1
2
3
4
5
set(CMAKE_C_COMPILER /ndk/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-gcc)
set(CMAKE_CXX_COMPILER /ndk/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-g++)
add_definitions("--sysroot=/ndk/sysroot")
# 必须指定一个编译类型,最后才能在 Clion 的 External Libraries 中生成头文件搜索路径
add_executable(run_rtc main.c)

虽然在命令行中也可以指定编译器类型,但是 Clion 不会自动生成头文件搜索路径,这样设置的结果就是只能用 Android 的 C 和 C++ 编译器,无法实现项目的跨平台(也许可以)。