Android studio NDK-JNI 编译so文件
文章懒的搬了大家直接看我开源中国的博客:
上篇我们编写了NDK代码了。也调用到了C/C++的方法,这篇我们来编译成动态库so文件,
在编译生成SO文件需要配下Android.mk文件
为什么需要这个文件Android.mk。当你需要使用JNI的时候,你需要创建一个native工程。Android.mk就是一个makefile配置文件,帮你把C/C++的代码编译成动态库so的。
我们来看下Android.mk文件内容
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hellojni
LOCAL_SRC_FILES := hajskdh.c
include $(BUILD_SHARED_LIBRARY)
解释下这几行代码:
LOCAL_PATH := $(call my-dir)
它用于在开发树中查找源文件。 在这个例子中,宏函数‘my-dir’, 由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录)。
include (CLEARVARS)CLEARVARS由编译系统提供(可以在android安装目录下的/build/core/config.mk文件看到其定义,为CLEARVARS:=(BUILD_SYSTEM)/clear_vars.mk),指定让 GNU MAKEFILE为你清除许多 LOCAL_XXX 变量 ( 例如 LOCAL_MODULE , LOCAL_SRC_FILES ,LOCAL_STATIC_LIBRARIES,等等…),除 LOCAL_PATH。这是必要的,因为所有的编译控制文件都在同一个 GNU MAKE 执行环境中,所有的变量都是全局的。
LOCAL_MODULE := hellojni
LOCAL_MODULE变量必须定义,以表示你在Android.mk文件中描述的每个模块名称必须是唯一的,通俗的说这个就是你最后生成so的名称,比如你填写的hellojni最后生成的就是libhellojni.so文件。注意:如果把库命名为‘libhellojni’,编译系统将不会添加任何的 lib 前缀,也会生成libhelloworld.so,这是为了支持来源于 Android平台的源代码的 Android.mk 文件。
LOCAL_SRC_FILES := hajskdh.c
LOCAL_SRC_FILES变量必须包含将要编译的打包进模块中的C/C++文件源码。这里不需要引用头文件。
include (BUILDSHAREDLIBRARY)BUILDSHAREDLIBRARY是编译系统提供的变量,指向一个GNUMakefile脚本(应该就是在build/core目录下的sharedlibrary.mk),负责收集自从上次调用‘include(CLEAR_VARS)’以来,定义在 LOCAL_XXX 变量中的所有信息,并且决定编译什么,如何正
确地去做。并根据其规则生成静态库。同理对于静态库。
Android.mk是必要文件,那么application.mk就是不是必要文件了。这个文件目的是描述在你的应用程序中所需要的模块(即静态库或动态库)。
APP_MODULES := hellojni
APP_ABI := all
这两行就相对简单,
APP_MODULES这个变量是可选的,如果没有定义,NDK将由在Android.mk中声明的默认的模块编译,并且包含所有的子文件(makefile文件)如果APP_MODULES定义了,它不许是一个空格分隔的模块列表,这个模块名字被定义在Android.mk文件中的LOCAL_MODULE中。
APP_ABI默认情况下,NDK的编译系统”armeabi”ABI生成机器代码。
all就表示所有类型都生成,
如果不需要全部只需要部分就可以设置APP_ABI := armeabi armeabi-v7a x86 这样就ok。
以上介绍是的编译SO需要的两个配置文件。那么接下来就正式编译so文件,找到之前hellojni项目的jni目录,在目录上右键选择ndk-build(在前篇有介绍的,不知道的同学可以过去看下)。点击完成就可以看到控制台输出的结果如下,
这里就会看到项目目录里面多生成了两个目录一个是libs,另一个是obj。libs下面就是编译生成的so对应的机器码,然后obj目录就没有什么用可以删除了。这里需要注意下obj这个目录在第二次编译之前请删除掉。不然二次编译就会收到影响。
删除的编译生成的文件可以使用ndk-build clear这个命令配置。这个命令就会清楚之前因编译生成的so相关文件,
我们在介绍另一种编译SO文件的办法,这种办法相对上面一种办法对依赖AS相对较少。
这里可以使用.sh脚本去执行编译SO文件操作。我们先介绍下.sh模板
#!/usr/bin/env bash
NDK_PROJECT_PATH=../
function build_so(){
ANDROID_MK=Android.mk
APPLICATION_MK=Application.mk
XXX/xxx/xxx/android-ndk-r12b/ndk-build -j8 NDK_TOOLCHAIN_VERSION=clang NDK_DEBUG=$1
#-platforms
}
#set_env
DEBUG=1
RELEASE=0;
build_so $RELEASE
以上就是build.sh的模板了。 直接将这段代码复制到文本后缀名改为.sh 然后将xxx/xxx/xxx/Android-ndk/ndk-build更改为你当前ndk的存放目录即可。
运行的话打开命令行进入到项目目录的jni目录下,然后执行sh build.sh文件即可得到同上面一样效果的文件目录结构。
以上还需要注意点内容就是:
通过AS编译出来的so文件配置是可以不需要依赖Aapplication.mk文件的。它对应的配置文件是build.gradle 中这个配置,所以在调整自己需要的so文件的时候注意下,
//定义使用ndk
ndk{
moduleName "hellojni" //生成的so名字
abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库。目前可有可无。
}
而通过脚本编译出来以来的文件就是Aapplication.mk所以最后在使用的时候记得分清楚。以免搞混乱了。