ndk-build 本质上是一个脚本,它的位置就在 NDK 目录的最上层,即在< NDK >/ndk-build 路径下。运行 ndk-build 脚本相当于运行以下命令:
$GNUMAKE -f <ndk>/build/core/build-local.mk
<parameters>
$GNUMAKE 指向 GNU Make 3.81 或更高版本, 则指向 NDK 安装目录。
官方文档链接
ndk-build 脚本使用 NDK 的基于 Make 的构建系统构建项目。使用 ndk-build我们需要两个配置文件: Android.mk 和 Application.mk。
Android.mk 更像是一个传统的 makefile,定义源代码、包含头文件的路径、链接器的路径来定位库、模块名、构建类型等等。
官方文档链接
Application.mk 定义了 Android 应用程序相关的属性,如 Android SDK 版本、调试或发布模式、目标平台 ABI (架构二进制接口)、标准 c/c++ 库等。
官方文档链接
在Android Studio 2.2 之后,工具中增加了 CMake 的支持,所以在 Android Studio 2.2 之后有2种方式来编译 c/c++ 代码。
如果非必须,不推荐使用 ndk-build 来构建,因为这样构建源码后,是无法使用方法跳转、方法提示等功能的!如果要改代码,就等于文本编辑器写代码。相反 CMake 是支持这些的,因此更有助于提高开发效率。所以这里就不详细说明 ndk-build 的使用步骤了,如果是新建项目就使用 CMake,如果是使用 ndk-build 的老项目,可以按照以下步骤转为 CMake。
软件环境:
Android Studio:3.6.3
JDK:1.8
NDK:21.2.6472646
android {
defaultConfig {
externalNativeBuild {
cmake {
cppFlags "-std=c++11 -stdlib=libc++ -fPIC -w"
arguments "-DANDROID_TOOLCHAIN=clang", "-DANDROID_STL=c++_shared", "-DANDROID_ARM_MODE=arm", "-DANDROID_ARM_NEON=TRUE", "-DANDROID_PLATFORM=android-21"
}
ndk {
abiFilters 'armeabi-v7a'
}
}
}
externalNativeBuild {
cmake {
path "src/main/jni/CMakeLists.txt"
version "3.10.2"
}
}
}
Application.mk中的 APP_PLATFORM 对应 arguments 中的 -DANDROID_PLATFORM;
Application.mk中的 APP_STL 对应 arguments 中的 -DANDROID_STL;
Application.mk中的 APP_ABI 对应 这里的 abiFilters;
Android.mk 中的 LOCAL_ARM_MODE 对应 arguments 中的 -DANDROID_ARM_MODE;
Android.mk 中的 LOCAL_ARM_NEON 对应 arguments 中的 -DANDROID_ARM_NEON。
相关配置对应关系如下:
Android.mk | CMakeLists.txt |
---|---|
LOCAL_MODULE、LOCAL_SRC_FILES | add_library |
LOCAL_CFLAGS | add_definitions |
LOCAL_C_INCLUDES | include_directories |
LOCAL_STATIC_LIBRARIES、LOCAL_SHARED_LIBRARIES | add_library + set_target_properties |
LOCAL_LDLIBS | find_library |
配置完成后,Android.mk 和 Application.mk 就不需要了。
(1)CMake Error: CMake was unable to find a build program corresponding to “Ninja”. CMAKE_MAKE_PROGRAM is not set. You probably need to select a different build tool.
编译时报错,修改工程的 build.gradle 的 com.android.tools.build:gradle 为更高版本。
(2)java.lang.UnsatisfiedLinkError: dlopen failed: library “xxxx.so” not found
运行时报错,这是由于 so 库并没有打包进 apk,所以找不到。
在 Android Studio 中,会默认匹配 src/main/jniLibs 目录,如果没有目录需要自己手动创建。如果想要使用其他路径的库,需要手动指定。
在 module 的 build.gradle 中添加:
sourceSets {
main {
jniLibs.srcDirs = ['libs'] //这里的ibs替换为存放so库的文件夹,不能在jni文件夹下
}
}
建议全部放在 jniLibs,不需要额外的任何配置。
通常我们把第三方提供的 h 文件夹,放在 src/main/cpp/include 里面,so 库放在 src/main/jniLibs/armeabi-v7a(不同 CPU 架构不同目录)下。