01-05 NDK开发必知必会3⃣️MakeFile详解

栏目: Android · 发布时间: 5年前

内容简介:C/C++语言基础 –> JNI编程 –> NDK编程 –> 音视频处理 –> 图像处理等等 ,从零到一 , 零基础学习NDK开发 。学习本专题 , 你需要具备一定的Android开发知识 C/C++基础, 知道如何创建一个Android工程 , 有一定的开发经验更佳 。Android.mk 的文件配置详解,能够读懂Android.mk;为何Google推荐使用cmake,而不在使用Android.mk?Android.mk存在哪些缺陷?如何生成静态库与动态库(在上几篇文章中讲过)?

C/C++语言基础 –> JNI编程 –> NDK编程 –> 音视频处理 –> 图像处理等等 ,从零到一 , 零基础学习NDK开发 。学习本专题 , 你需要具备一定的Android开发知识 C/C++基础, 知道如何创建一个Android工程 , 有一定的开发经验更佳 。

前言

Android.mk 的文件配置详解,能够读懂Android.mk;为何Google推荐使用cmake,而不在使用Android.mk?Android.mk存在哪些缺陷?

如何生成静态库与动态库(在上几篇文章中讲过)?

Android.mk 如何配置动态库(.so文件)、配置静态库(.a文件)?

静态库与动态库的区别?

带着这些问题,思考,往下看。

环境:

AS 3.1.0 版本

NDK 16 版本

命令行: Mac 自带的命令行

通过命令来生成动态库和静态库

这里用mac的终端来演示,通过vim 命令来生成一个.c文件,这个就不必细说了吧。 在NDK 开发必知必会1⃣️CC++编译器配置,中有详细的讲解

输入: vim a.c

01-05 NDK开发必知必会3⃣️MakeFile详解

然后配置一个临时的变量:

export CC="/Users/prim/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-gcc --sysroot=/Users/prim/Library/Android/sdk/ndk-bundle/platforms/android-21/arch-arm -isystem /Users/prim/Library/Android/sdk/ndk-bundle/sysroot/usr/include -isystem /Users/prim/Library/Android/sdk/ndk-bundle/sysroot/usr/include/arm-linux-androideabi"

输入 :echo $CC 验证变量是否配置成功

输入 :$CC -fPIC -shared a.c -o libA.so 生成libA.so文件,这里便生成了一个动态库

输入:$CC -fPIC -c a.c -o a.o 生成a.o 文件,用于生成静态库

输入 : /Users/prim/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ar r libA.a a.o

会生成libA.a 静态库文件。

将得到的libA.so libA.a copy到项目的cpp 文件夹下( cpp可参照如何配置NDK开发环境 )。

配置依赖动态库

NDK 环境的配置,这里就不再细说了,配置完成如下图:

01-05 NDK开发必知必会3⃣️MakeFile详解

gradle 配置

01-05 NDK开发必知必会3⃣️MakeFile详解

下面是重点,Android.mk文件如何配置动态库

LOCAL_PATH := $(call my-dir)

# 预编译库引入(提前编译好的库)
include $(CLEAR_VARS)
LOCAL_MODULE := A
LOCAL_SRC_FILES := libA.so
# 构建动态库
include $(PREBUILT_SHARED_LIBRARY)


include $(CLEAR_VARS)
LOCAL_MODULE := holle-jni
LOCAL_SRC_FILES := holle-jni.c
# 编译holle-jni模块 需要连接A模块
# A模块是一个预编译库模块 动态库
LOCAL_SHARED_LIBRARIES := A
# 动态库配置
include $(BUILD_SHARED_LIBRARY)

LOCAL_PATH := $(call my-dir)表示:源文件在的位置。宏函数 my-dir 返回当前目录(包含 Android.mk 文件本身的目录)的路径。

include $(CLEAR_VARS):引入其他makefile文件。CLEAR_VARS 变量指向特殊 GNU Makefile,可为您清除许多 LOCAL_XXX 变量

不会清理 LOCAL_PATH 变量

LOCAL_MODULE := hello-jni:存储您要构建的模块的名称 每个模块名称必须唯一,且不含任何空格

#如果模块名称的开头已是 lib,则构建系统不会附加额外的前缀 lib;而是按原样采用模块名称,并添加 .so 扩展名。

LOCAL_SRC_FILES := hello-jni.c:包含要构建到模块中的 C 和/或 C++ 源文件列表 以空格分开

构建动态库 include $(BUILD_SHARED_LIBRARY)

这样便配置好了动态库,build一下看cpp文件有没有变亮,如果变亮则动态库配置成功。

会生成两个so包libholle-jni.so libA.so

01-05 NDK开发必知必会3⃣️MakeFile详解

如何使用libA.so中的函数呢?

编辑 holle-jni.c

#include <jni.h>
//libA.so 中的方法
extern int test1();



JNIEXPORT void JNICALL
Java_ndk_config_com_configndk_MainActivity_useLibAMoudle(JNIEnv *env, jobject instance) {

    // TODO
    test1();
}

Activity 中代码

static {
        System.loadLibrary("holle-jni");
    }

这样就可以调用动态库中的函数了。

Android.mk 配置动态库的缺陷

在4.4上 如果load一个动态库 ,需要先将这个动态库的依赖的其他动态库load进来

比如:在Android 4.4 先要load holle-jni 链接的动态库,要在load holle-jni 之前load进来

System.loadLibrary("A");
 System.loadLibrary("holle-jni");

从6.0开始 使用Android.mk 如果来引入一个预编译动态库 有问题

在6.0以下 System.loadLibrary 不会自动为我们加载依赖的动态库

6.0以上 System.loadLibrary 会自动为我们加载依赖的动态库

那么在6.0 以上就不能使用,如下方法loadlibary,否则项目会报错:

System.loadLibrary("A");
 System.loadLibrary("holle-jni");

改成,因为6.0以上会自动加载依赖的动态库。

System.loadLibrary("holle-jni");

这里并没有太好的解决方法,或许是因为这个原因,Google才推荐使用cmake的方式,现在的ndk对mk的支持已经接近放弃阶段了。

配置依赖静态库

LOCAL_PATH := $(call my-dir)

# 预编译库引入(提前编译好的库)
include $(CLEAR_VARS)
LOCAL_MODULE := A
LOCAL_SRC_FILES := libA.a
# 构建静态库
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := holle-jni
LOCAL_SRC_FILES := holle-jni.c
# 构建静态库
LOCAL_STATIC_LIBRARIES := A

# 动态库配置
include $(BUILD_SHARED_LIBRARY)

调用静态库的函数和调用动态库的函数方式一致。

同时Activity只需要,便可以,静态库不需要动态的加载依赖,在打包时已经将静态库打进去了。

System.loadLibrary("holle-jni");

使用静态库会生成一个so文件,很显然apk会小很多

01-05 NDK开发必知必会3⃣️MakeFile详解

静态库与动态库的区别

静态库节省时间:不需要再进行动态链接,需要调用的代码直接就在代码内部

动态库节省空间:如果一个动态库被两个程序调用,那么这个动态库只需要在内存中

Java中在不经过封装的情况下只能直接使用动态库。

我们可以这样比喻两个库的区别:

jar包 =》 a.java b.java c.java

app: app.java(a.java),app.java 调用jar包的 a.java

假设jar包是静态库,那么打包的apk 只包含 app.java + a.java 而没有将 b.java c. java 打进apk包中。

app.apk –> app.java+a.java

假设jar包是动态库,直接将整个jar包打入到apk包中。

app.apk: app.java+ jar包(a.java b.java c.java)

显然,如果我们使用静态库(.a)打的apk包要比动态库(.so)打的apk包小很多。

MakeFile 配置详解

变量和宏

定义自己的任意变量。在定义变量时请注意,NDK 构建系统会预留以下变量名称:

以 LOCAL_ 开头的名称,例如 LOCAL_MODULE。

以 PRIVATE_、NDK_ 或 APP 开头的名称。构建系统在内部使用这些变量。

小写名称,例如 my-dir。构建系统也是在内部使用这些变量。

如果为了方便而需要在 Android.mk 文件中定义自己的变量,建议在名称前附加 MY_。

常用内置变量

变量名 含义 示例
BUILD_STATIC_LIBRARY 构建静态库的Makefile脚本 include $(BUILD_STATIC_LIBRARY)
PREBUILT_SHARED_LIBRARY 预编译共享库的Makeifle脚本 include $(PREBUILT_SHARED_LIBRARY)
PREBUILT_STATIC_LIBRARY 预编译静态库的Makeifle脚本 include $(PREBUILT_STATIC_LIBRARY)
TARGET_PLATFORM Android API 级别号 TARGET_PLATFORM := android-22
TARGET_ARCH CUP架构 arm arm64 x86 x86_64
TARGET_ARCH_ABI CPU架构 armeabi armeabi-v7a arm64-v8a

模块描述变量

变量名 描述
LOCAL_MODULE_FILENAME 覆盖构建系统默认用于其生成的文件的名称 LOCAL_MODULE := foo LOCAL_MODULE_FILENAME := libnewfoo
LOCAL_CPP_FEATURES 特定 C++ 功能 支持异常:LOCAL_CPP_FEATURES := exceptions
LOCAL_C_INCLUDES 头文件目录查找路径 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_CFLAGS 构建 C 和 C++ 的编译参数 LOCAL_CPPFLAGS c++
LOCAL_STATIC_LIBRARIES 当前模块依赖的静态库模块列表 LOCAL_SHARED_LIBRARIES
LOCAL_WHOLE_STATIC_LIBRARIES –whole-archive 将未使用的函数符号也加入编译进入这个模块
LOCAL_LDLIBS 依赖 系统库 LOCAL_LDLIBS := -lz

导出给引入模块的模块使用:

LOCAL_EXPORT_CFLAGS

LOCAL_EXPORT_CPPFLAGS

LOCAL_EXPORT_C_INCLUDES

LOCAL_EXPORT_LDLIBS

引入其他模块

#将一个新的路径加入NDK_MODULE_PATH变量
#NDK_MODULE_PATH 变量是系统环境变量
$(call import-add-path,$(LOCAL_PATH)/platform/third_party/android/prebuilt)
#包含CocosDenshion/android目录下的mk文件
$(call import-module,CocosDenshion/android)

#这里即为 我需要引入 CocosDenshion/android 下面的Android.mk
#CocosDenshion/android 的路径会从 $(LOCAL_PATH)/platform/third_party/android/prebuilt 去查找

以上所述就是小编给大家介绍的《01-05 NDK开发必知必会3⃣️MakeFile详解》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

JSP应用开发技术

JSP应用开发技术

柳永坡 / 人民邮电出版社 / 2005-9 / 52.00元

本书全面系统地介绍了JSP应用开发技术,包括JSP预备知识和环境配置、JSP编程基础、JSP应用开发进阶、在JSP中使用数据库、Servlet技术、标签库和表达式语言、Web编程模式和应用框架等几个方面的内容。本书不但由浅入深地介绍了JSP程序设计的原理、方法和技术,还提供了大量的JSP应用开发实例,给出了相应的实用技巧、操作步骤及优化思路。 本书着重于JSP技术的应用性和可操作性,......一起来看看 《JSP应用开发技术》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具