加载静态库到android,静态库的提供方式有2种, css
a. 经过源文件来编译静态库 html
b. 加载已经编译好的静态库 java
首先咱们来看,经过源文件来编译静态库,工程目录以下 android
第一步:咱们来看咱们的jni目录,目录下包含如下4个文件 windows
Android.mk --- 编译文件 ide
first.c ,first.h --- 外部须要引用的文件 ui
second.c ---- 咱们的jni转换文件 this
首先咱们简单的看下源码spa
#include "first.h" int first(int x, int y) { return x + y; }
first.c里面简单的定义了一个加法的方法,而后申明了头文件
second.c : 把first.c的方法转换为jni能够识别的方法。3d
#include "first.h" #include <jni.h> jint Java_com_example_twolibs_TwoLibs_add( JNIEnv* env, jobject this, jint x, jint y ) { return first(x, y); }
第二步是重点,咱们来分析下mk文件,看编译文件是怎样生成first.c对于的静态文件,并在编译second.c的时候加载静态文件
1: LOCAL_PATH:= $(call my-dir)
2:
3: # first lib, which will be built statically
4: #
5: include $(CLEAR_VARS)
6:
7: LOCAL_MODULE := libtwolib-first
8: LOCAL_SRC_FILES := first.c
9:
10: include $(BUILD_STATIC_LIBRARY)
11:
12: # second lib, which will depend on and include the first one
13: #
14: include $(CLEAR_VARS)
15:
16: LOCAL_MODULE := libtwolib-second
17: LOCAL_SRC_FILES := second.c
18:
19: LOCAL_STATIC_LIBRARIES := libtwolib-first
20:
21: include $(BUILD_SHARED_LIBRARY)
如上: 1-10 行是生成静态文件的方法,
14-21 行是编译动态文件的方法,经过标识符BUILD_SHARED_LIBRARY 以及 BUILD_STATIC_LIBRARY 来区分是编译成动态文件仍是静态,19行标识须要连接静态库libtwolib-first
第三步:在java中调用
public class TwoLibs extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv = new TextView(this); int x = 1000; int y = 42; // here, we dynamically load the library at runtime // before calling the native method. // System.loadLibrary("twolib-second"); int z = add(x, y); tv.setText( "The sum of " + x + " and " + y + " is " + z ); setContentView(tv); } public native int add(int x, int y); }
第二种方法: 用第3方提供的静态库来编译,咱们仍是用前面的jni文件
首先第一步咱们经过gcc来生成静态库文件
gcc -c first.c 生成.o文件
ar -cr libtwolib-first.a first.o 来生成libtwolib-first.a库文件
而后经过 查看,方法多了一个”_”,这个坑爹了,还不知道怎么处理,网上没找到方法,这种方法只能先放放了。
那既然第一种不行,那是否是能够直接用原来的.mk文件来生成了,尝试了下,修改了mk文件,注释掉生成动态库的一部分。
LOCAL_PATH:= $(call my-dir) # first lib, which will be built statically # include $(CLEAR_VARS) LOCAL_MODULE := libtwolib-first LOCAL_SRC_FILES := first.c include $(BUILD_STATIC_LIBRARY) # second lib, which will depend on and include the first one # #include $(CLEAR_VARS) #LOCAL_MODULE := libtwolib-second #LOCAL_SRC_FILES := second.c #LOCAL_STATIC_LIBRARIES := libtwolib-first #include $(BUILD_SHARED_LIBRARY)
而后执行 ndk-build 什么反应都没有,通过查找一位大拿解决了,须要修改配置文件
NDK r6 默认不支持静态库的 install 操做。能够将 definitions.mk 脚本里的 D:\cygwin\home\Administrator\android-ndk-r8b\build\core\definitions.mk 1669行 module-class-is-installable = $(if $(NDK_MODULE_CLASS.$1.INSTALLABLE),$(true),$(false)) 修改成: module-class-is-installable = $(if $(NDK_MODULE_CLASS.$1.INSTALLABLE),$(true),$(true)) 这样强制 NDK 对静态库进行 install,便可单独生成静态库
修改完之后,执行ndk-build,果真在/libs/armeabi目录下找到了库文件libtwolib-first.a
方法也正常。
而后把.a文件拷贝到jni目录下,修改mk文件,去掉生成静态库部分,编译报错,找不到方法
通过查找才知道 “编译器改为windows版的了,/cygdrive/开头的cygwin下的路径再也不支持,使用windows路径就能够了”
因此从新修改mk文件为以下
/usr/lib/gcc/i686-pc-cygwin/4.5.3/cc1.exe: error while loading shared libraries:
cygppl_c-2.dll: cannot open shared object file: No such file or directory
不用着急,这是由于在安装时,没有安装mpfr(版本4)所至,打开cygwin.exe,输入mpfr,下载libmpfr4至可
将NDK编译的第三方静态拷贝到JNI目录下,在Android.mk中添加以下代码
以openssl静态库(libcrypto-static.a)为例
第一种连接方法:LOCAL_LDFLAGS := libcrypto-static.a
第二种连接方法:LOCAL_LDLIBS := libcrypto-static.a
第三种连接方法:
include $(CLEAR_VARS)
LOCAL_MODULE := third_static_lib (能够随便起一个名字)
LOCAL_SRC_FILES := libcrypto-static.a
include $(PREBUILT_STATIC_LIBRARY)
//在你要编译的模块中引用third_static_lib
LOCAL_STATIC_LIBRARIES := third_static_lib
标签:
项目编译成动态库是正常的,将 Android.mk 里面的
include $(BUILD_SHARED_LIBRARY)
改为
include $(BUILD_STATIC_LIBRARY)
编译静态库,
运行 ndk-build 却一点反应都没有,一闪而过。
解决方案:
在 工程目录\jni\ 目录下添加一个 Application.mk 文件,里面只写上以下一行代码:
APP_MODULES := lib库名
问题解决。
目录结构示意图:
工程目录
|-jni
| |-*.c/*.h <--多个源文件
| |-Android.mk
| |-Application.mk
|
|-Application.mk
1.工程目录/jni/Android.mk 文件内容:
# 提供当前文件的路径,必须定义它在你的 Android.mk 文件的开始处
LOCAL_PATH := $(call my-dir)
# CLEAR_VARS 变量是由生成系统已提供的,
# 而且指出一个特殊的 GNU Makefile 文件为你清除除了 LOCAL_PATH 之外的许多的 LOCAL_* 变量,
# 这是必须的,由于所有的生成控制文件是在一个单独的 GNU Make 执行环境中被分析的,
# 在那里全部的变量是全局的。
include $(CLEAR_VARS)
# 该变量是必须定义的,用来标识你的 Android.mk 文件中描述的每一个模块,
# 模块名字必须是惟一的,而且不能包含任何的空格。
LOCAL_MODULE:= 模块名字
# 该变量是必须包含将要生成且汇编成一个模块所需的 C / C++ 源文件的列表。
# 注意:不列出头文件和包含文件在这里,由于生成系统将自动地为你估算信赖。
LOCAL_SRC_FILES := 多个源代码文件(*.c)用空格分隔
# 一个可选的路径列表,作为 include 搜索路径之一。
LOCAL_C_INCLUDES := $(LOCAL_PATH)
#include $(BUILD_SHARED_LIBRARY)
include $(BUILD_STATIC_LIBRARY)
2.工程目录/jni/Application.mk 文件内容:
# 该变量是可选的,指出你的应用程序工程名
APP_MODULES := lib模块名字
3.工程目录/Application.mk 文件内容:
# 该文件是可选的,用来描述你的工程的更多细节,如:支持更多 CPU 以及替代编译器或连接器标志。
# 指出你的应用程序工程目录
APP_PROJECT_PATH := $(call my-dir)
# 默认状况下,NDK 生成系统将寻找一个名为 Android.mk 文件在 $(APP_PROJECT_PATH)/jni 目录下
APP_BUILD_SCRIPT := $(APP_PROJECT_PATH)/jni/Android.mk
注:工程目录/jni/Application.mk 文件内容,
在编译动态库时,能够合并到 工程目录/Application.mk 文件内容 中。