NDK ndk build 和 cmake构建方式介绍

一、NDK 基础概念

在介绍 NDK 之前还是首推 Android 官方 NDK 文档。

首先用简单的话分别解释下 JNI、NDK, 以及分别和 Android 开发、c/c++ 开发的配合。在解释过程中会对 Android.mk、Application.mk、ndk-build、CMake、CMakeList 、gradle-experimental进行说明,并从发展的历史中,讲一讲它们诞生的原因。

JNI(Java Native Interface):Java本地接口。是为了方便Java调用c、c++等本地代码所封装的一层接口(也是一个标准)。大家都知道,Java的优点是跨平台,但是作为优点的同时,其在本地交互的时候就编程了缺点。Java的跨平台特性导致其本地交互的能力不够强大,一些和操作系统相关的特性Java无法完成,于是Java提供了jni专门用于和本地代码交互,这样就增强了Java语言的本地交互能力。

NDK(Native Development Kit) : 原生开发工具包,即帮助开发原生代码的一系列工具,包括但不限于编译工具、一些公共库、开发IDE等。

构建

在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

Android.mk 文件位于项目 jni/ 目录的子目录中,用于向构建系统描述源文件和共享库。 它实际上是构建系统解析一次或多次的微小 GNU makefile 片段。 Android.mk 文件用于定义 Application.mk、构建系统和环境变量所未定义的项目范围设置。 它还可替换特定模块的项目范围设置。

Application.mk:它是一个构建文件,此文件用于描述应用需要的原生模块。 模块可以是静态库、共享库或可执行文件。实际上是定义要编译的多个变量的微小 GNU Makefile 片段。

NDK 工具包中提供了完整的一套将 c/c++ 代码编译成静态/动态库的工具,而 Android.mk 和 Application.mk 你可以认为是描述编译参数和一些配置的文件。比如指定使用c++11还是c++14编译,会引用哪些共享库,并描述关系等,还会指定编译的 abi。只有有了这些 NDK 中的编译工具才能准确的编译 c/c++ 代码。

ndk-build文件 是 Android NDK r4 中引入的一个 shell 脚本。为了调用正确的 NDK 构建脚本。其实最终还是会去调用 NDK 自己的编译工具。

第二种:CMake

代码变成可执行文件,需要经过编译、链接、生成可执行文件;
先编译哪个文件(编译的安排)叫做构建(build)。将这些构建规则写到一个文件中,让程序去执行。不同的编译工具,使用的构建文件不一样。

CMake是个一个开源的跨平台自动化建构系统,用来管理软件建置的程序,并不依赖于某特定编译器,并可支持多层目录、多个应用程序与多个库。 它用配置文件控制建构过程(build process)的方式和Unix的make相似,只是CMake的配置文件取名为CMakeLists.txt。CMake并不直接建构出最终的软件,而是产生标准的建构档(如GNU的Makefile或Windows Visual C++的projects/workspaces),然后再依一般的建构方式使用。

NDK 下的CMake官方文档

CMake可与 Gradle 搭配使用,构建原生库。


Experimental Android plugin在发展的过程中,曾经出现过实验性的gradle和Android插件( experimental Android plugin),它包括用于构建JNI应用程序的NDK集成,但是由于所依赖的组件模块不在支持,Gradle也在支持C/C++的路上,所以这个实验性的experimental Android plugin已经不在支持了。官方文档

二、遇到的一些问题

NDK调试问题:

在使用AS调试NDK代码的时候,出现一些问题,java中的jni函数红名,之前也出现过,在网上找了好多,也询问了鹅场的技术,他说有可能是AS不稳定。确实我重新安装AS,jni函数会显示正常,但不知道怎么一下jni函数就又红名了。

最近又去搞了一下这个问题,把过程总结了一下,

操作流程 工程 状态 更改 更改后改变的状态
1 B工程 1、ndkbuild
2、jni函数正常(函数颜色不是红色,可以跟进去c++代码)
3、不能调试。
不能调试
2 A工程 1、ndkbuild
2、jni函数正常
3、不能调试。
使用gradle-experimental 可以调试
3 B工程 1、ndkbuild
2、jni函数正常
3、不能调试。
A工程使用gradle-experimental后 jni函数显示红色.(难道需要invalidate cache and restart)
把ndkbuild 工程换成 cmake jni函数正常
没有使用 gradle-experimental 也能调试
4 A工程 去掉gradle-experimental 可以调试
jni函数正常

网上有人说NDK调试需要gradle-experimental,但是官方文档并没有提这个。我后来没有使用gradle-experimental,确实也可以调试。

Android Studio NDk调试(基于gradle-experimental插件与LLDB)
官方文档:https://developer.android.com/studio/debug/index.html

我得出的结论是:

1. 调试不需要gradle-experimental
2. 最好使用cmake编译ndk代码。

有朋友知道原因的可以指点一下

gradle-experimental与gradle版本对应关系

在官方文档中, Experimental Plugin User Guide这个对应关系只更新到gradle 2.14.1

后来我找来找去,我想既然文档没有,源码中应该有这个关系的代码吧。果然被我发现了

在这里查看gradle-experimental的历代版本,其中包括源码。找到.pom文件,其中声明使用’com.android.tools.build’ 的gradle-core版本,跟你的AS版本一致的就能用。

遇到这么一个事情,分享给大家,我是在2017.5.12早上更新的AS 版本是2.3.2,在查找.pom文件的时候,发现0.9.1的gradle-experimental,依赖com.android.tools.build的gradle-core: 版本2.3.1,在往上找0.10.0-alpha1,却依赖com.android.tools.build的gradle-core: 版本是2.4.0-alpha1’。找了半天没找到2.3.2的版本,于是就用了0.9.1的gradle-experimental,结果sync project的时候提示更新到0.9.2。这说明0.9.2的版本是存在的。

当时好奇怪,结果第二天这里就出现了0.9.2版本

https://bintray.com 网站更新库,可能不是很及时,所以如果没找到自己要的,可以先直接用上

CMake和ndkbuild使用过程的一些情况

B工程使用ndkbuild的时候,使用的是r10,使用13.1.3345770会出现这个错误。 但使用cmake后,使用13.1.3345770也正常了。

不知道是mk文件配置不正确,还是ndkbuild不兼容13.1的原因。有朋友知道原因的可以指点一下

参考:
Android NDK开发扫盲及最新CMake的编译使用
Make 命令教程
cmake 简介
什么是Makefile?

关注我的公众号,轻松了解和学习更多技术
这里写图片描述

你可能感兴趣的:(NDK)