1 概念

ndk-build 本质上是一个脚本,它的位置就在 NDK 目录的最上层,即在< NDK >/ndk-build 路径下。运行 ndk-build 脚本相当于运行以下命令:

$GNUMAKE -f <ndk>/build/core/build-local.mk
<parameters>

$GNUMAKE 指向 GNU Make 3.81 或更高版本, 则指向 NDK 安装目录。

官方文档链接

2 组成

ndk-build 脚本使用 NDK 的基于 Make 的构建系统构建项目。使用 ndk-build我们需要两个配置文件: Android.mkApplication.mk

2.1 Android.mk

Android.mk 更像是一个传统的 makefile,定义源代码、包含头文件的路径、链接器的路径来定位库、模块名、构建类型等等。

  • LOCAL_PATH :=$(call my-dir)
    返回当前文件在系统中路径,Android.mk 文件开始时必须定义该变量。
  • include $(CLEAR_VARS)
    表明清楚上一次构建过程的所有全局变量,因为在一个 Makefile 编译脚本中,会使用大量的全局变量,使用这行脚本表明需要清除掉所有的全局变量。
  • LOCAL_SRC_FILES
    要编译的 C 或者 CPP 的文件,注意这里不需要列举头文件,构建系统会自动帮组开发者依赖这些文件。
  • LOCAL_LDLIBS:=-L$ (SYSROOT)/usr/lib -llog -lOPENSLES -lGLESv2 -lEGL -lz
    指定编译过程所依赖的 NDK 提供的动态和静态库,SYSROOT变量代表的是 NDK_ROOT 下面的目录 $NDK_ROOT/platforms/android-18/arch-arm,而在这个目录的 usr/lib/ 目录下有很多对应的 .so 的动态库以及 .a 的静态库。
  • LOCAL_CFLAGS
    编译 C 或者 CPP 的编译标志,在实际编译的时候会发送给编译器。比如常用的实例是加上 -DAUTO_TEST , 然后在代码中就可以利用条件判断 #ifdef AUTO_TEST 来做一些与自动化测试相关的事情。
  • LOCAL_LDFLAGS
    链接标志的可选列表,当对目标文件进行链接以生成输出文件的时候,将这些标志带给链接器。该指令与 LOCAL_LDLIBS 有些类似,一般情况下,该选项会用于指定第三方编译的静态库,LOCAL_LDLIBS 经常用于指定系统的库(比如 log、OpenGLES、OpenSLES 等)。
  • LOCAL_MODULE
    该模块的编译的目标名,用于区分各个模块,名字必须是唯一并不包含空格的,如果编译目标是 so 库,那么该 so 库的名称就是 lib 项目名 .so。
  • include $(BUILD_SHARED_LIBRARY)
    其实类似的 include 还有很多,都是构建系统提供的内置变量,该变量的意义是构建动态库,其他的内置变量还包括如下几种。

    • BUILD_STATIC_LIBRARY: 构建静态库
    • PREBUILT_STATIC_LIBRARY: 对已有的静态库进行包装,使其成为一个模块。
    • PREBUILT_SHARED_LIBRARY: 对已有的静态库进行包装,使其成为一个模块。
    • BUILD_EXECUTABLE: 构建可执行文件。

官方文档链接

2.2 Application.mk

Application.mk 定义了 Android 应用程序相关的属性,如 Android SDK 版本、调试或发布模式、目标平台 ABI (架构二进制接口)、标准 c/c++ 库等。

  • APP_ABI := XXX,这里的 XXX 是指不同平台,可以选填的有 x86 、X86_64 、armeabi-v8a、armeabi-v7a、all 等,值得一提的是,若选择 all 则会构建构建出所有平台的 so,如果不填写该项,那么将默认构建为 armeabi 平台下的库。
  • APP_STL := gnustl_static,NDK 构建系统提供了由 Android 系统给出的最小 C++ 运行时库 (system/lib/libstdc++.so)的 C++ 头文件。
  • APP_CPPFLAGS :=-std=gnu++11 -fexceptions,指定编译过程的 flag ,可以在该选项中开启 exception rtti 等特性,但是为了效率考虑,最好关闭 rtti。
  • NDK_TOOLCHAIN_VERSION = 4.8,指定交叉工具编译链里面的版本号,这里指定使用 4.8。
  • APP_PLATFORM :=android-21,指定创建的动态库的平台
  • APP_OPTIM := release,该变量是可选的,用来定义 “release” 或者 “debug” ,“release” 模式是默认的,并且会生成高度优化的二进制代码;“debug” 模式生成的是未优化的二进制代码,但是可以检测出很多的 BUG,经常用于调试阶段,也相当于在 ndk-build 指令后边直接加上参数 NDK_DEBUG=1。

官方文档链接

3 ndk-build 转换为 CMake

在Android Studio 2.2 之后,工具中增加了 CMake 的支持,所以在 Android Studio 2.2 之后有2种方式来编译 c/c++ 代码。

  • 一种是 ndk-build + Android.mk + Application.mk 的方式
  • 另一种是 CMake + CMakeLists.txt 的方式
    这两种方式与 Android 代码和 c/c++ 代码无关,只是不同的构建脚本和构建命令。

如果非必须,不推荐使用 ndk-build 来构建,因为这样构建源码后,是无法使用方法跳转、方法提示等功能的!如果要改代码,就等于文本编辑器写代码。相反 CMake 是支持这些的,因此更有助于提高开发效率。所以这里就不详细说明 ndk-build 的使用步骤了,如果是新建项目就使用 CMake,如果是使用 ndk-build 的老项目,可以按照以下步骤转为 CMake。

3.1 操作步骤

软件环境:
Android Studio:3.6.3
JDK:1.8
NDK:21.2.6472646

3.1.1 修改 module 下的 build.gradle

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

3.1.2 新建 CMakeLists.txt

相关配置对应关系如下:

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 就不需要了。

3.2 常见问题及解决方案

(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 架构不同目录)下。

NDK 开发之 ndk-build 的使用相关推荐

  1. Android studio中的NDK开发之NDK环境变量的配置(图文教程)

    为什么总是图文教程? 因为本人对抽象事物联想不到位,更喜欢具体能看到的东西,简单明了,一目了然,更是一步到位!如下图: 第一步找到你通过android studio下载好的NDK目录,如果不知道下载到 ...

  2. Android NDK开发之 NDK 局部 全局引用

    http://my.oschina.net/ososchina/blog/366735

  3. Android NDK开发之 NDK类型签名

    转自: http://www.cnblogs.com/luxiaofeng54/archive/2011/08/18/2143977.html

  4. Android NDK开发之旅31 FFmpeg音频解码

    ###前言 #####基于Android NDK开发之旅30--FFmpeg视频播放这篇文章,我们已经学会视频解码基本过程.这篇文章就对音频解码进行分析. #####音频解码和视频解码的套路基本是一样 ...

  5. Android NDK开发之 NEON基础介绍

    原文:http://blog.csdn.net/app_12062011/article/details/50434259 Android NDK开发之 NEON基础介绍 这是官方介绍: http:/ ...

  6. Android NDK开发之旅1 NDK介绍

    ###一.NDK产生的背景 Android平台从诞生起,就已经支持C.C++开发.众所周知,Android的SDK基于Java实现,这意味着基于Android SDK进行开发的第三方应用都必须使用Ja ...

  7. NDK开发之CMake编译构建原生库

    参考地址:https://blog.csdn.net/liu3364575/article/details/80091506                 https://blog.csdn.net ...

  8. Android NDK开发之旅29 云服务器Ubuntu下搭建NDK环境,并编译FFmpeg

    ###前言 因为在Linux环境下编译FFmpeg生成库和头文件下比较方便,所以接下来主要操作在Linux环境下进行.但是对于Android NDK 开发新手来说,自己电脑配置Ubuntu Linux ...

  9. AndroidStudio2.2 Preview3中NDK开发之CMake和传统 JNI在目录结构和配置文件上的区别

    自从AndroidStudio更新到2.2,就有了CMake和传统JNI两种开发NDK的方法,主要就是在目录结构和build.gradle上的区别,下面我们将分别介绍目录区别和build.gradle ...

  10. Android NDK开发之旅25 NDK 模仿QQ变声特效

    ###前言 我们这次用到的是fmod这个库,fmod是音效引擎游戏开发革命引擎,著名的游戏开发引擎CosCos2D.U3D都封装了这个库. 学习NDK的目的就是为了让我们的APP能够使用C/C++开源 ...

最新文章

  1. 双轴机械臂建模分析数据
  2. XenStore: 使用,结构和原理
  3. 计算机网络多媒体图像矢量图,13多媒体信息处理——图像处理(一)
  4. inv(a) matlab,在MATLAB中,inv(A)表示的是()
  5. matlab拟合四次函数表达式,用matlab编写程序求以幂函数作基函数的3次、4次多项式的最小二乘曲线拟合,画出数据散点图及拟合曲线图...
  6. 深度学习知识体系总结(2021版)开放下载了!
  7. a new weekday
  8. 计算机软件水平考试程序员之程序设计知识点汇总,计算机软件水平考试《程序员》复习知识点(5)...
  9. 可转债第三课:如何赚取可转债的高收益
  10. 7. gdal进行遥感影像的16位转8位和百分比截断增强(看这篇就够了)
  11. GRV – 可视化git仓库工具
  12. 什么是裸金属服务器?
  13. 无线路由器无法在计算机上设置,无线路由器设置管理地址无法打开解决方法
  14. 救救我吧,今年27岁,想转行学大数据开发
  15. java五子棋棋盘_java绘制五子棋棋盘代码示例
  16. Java高级编程3-姜国海
  17. PHP中的网络编程 -- Socket篇
  18. html空格的使用 emsp ensp nbsp; thinsp; zwnj;  zwj;
  19. 金融科技浪潮下的保理行业发展新热点
  20. onenote需要密码才能同步此笔记本。 (错误代码: 0xE0000024)

热门文章

  1. 【C++】win 10:VC 6.0 中文版下载、安装、使用
  2. ZSC 1526 独眼贝斯基 (KMP + 优化)
  3. Trans论文的发表流程(George E.Ponchak)
  4. 2022河海大学物联网工程学院电子信息(计算机与软件方向)890上岸经验帖(毕业2年后,双非三跨211成功)
  5. DIT-FFT[C语言实现]
  6. 个人版的一键GHOST工具V1.0 BY何定坤
  7. 在合并单元格设置编号—“count-a函数”的使用
  8. oracle 自动填充,jQuery 实现自动填充邮箱功能(带下拉提示)
  9. 离散数学 学习笔记-Day4
  10. Above the MedianDueling GPSs