zoukankan      html  css  js  c++  java
  • NDK jni 加载静态库

    加载静态库到android,静态库的提供方式有2种,

    a. 通过源文件来编译静态库

    b. 加载已经编译好的静态库

    首先我们来看,通过源文件来编译静态库,工程目录如下

    image

    第一步:我们来看我们的jni目录,目录下包含以下4个文件

    Android.mk  --- 编译文件

    first.c ,first.h --- 外部需要引用的文件

    second.c  ---- 我们的jni转换文件

    首先我们简单的看下源码

    #include "first.h"
    
    int first(int  x, int  y)
    {
        return x + y;
    }
    first.c里面简单的定义了一个加法的方法,然后申明了头文件
     
     

    second.c : 把first.c的方法转换为jni可以识别的方法。

    #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库文件

       然后通过image 查看,方法多了一个”_”,这个坑爹了,还不知道怎么处理,网上没找到方法,这种方法只能先放放了。

    那既然第一种不行,那是不是可以直接用原来的.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:cygwinhomeAdministratorandroid-ndk-r8buildcoredefinitions.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
    image 方法也正常。
     
    然后把.a文件拷贝到jni目录下,修改mk文件,去掉生成静态库部分,编译报错,找不到方法
    image 

        

          经过查找才知道 “编译器改成windows版的了,/cygdrive/开头的cygwin下的路径不再支持,使用windows路径就可以了”

         所以重新修改mk文件为如下

         image

             

     

    /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 链接第三方静态库的方法

    将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

    解决 NDK 编译静态库时没反应

    (2012-12-11 14:22:02)

    转载

    标签:

    杂谈

    分类: Android

    项目编译成动态库是正常的,将 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 文件内容 中。

  • 相关阅读:
    Linux启动mysql命令
    Linux启动Apache服务器命令
    使用SSH命令从一台Linux远程登陆到另一台Linux
    Linux关机命令
    从Windows复制文件到Linux
    无法访问SVN历史记录的问题
    linux静态IP最简配置
    学习之Redis(二)
    学习之Redis(一)
    MySQL数据库笔记总结
  • 原文地址:https://www.cnblogs.com/zhangweia/p/3361711.html
Copyright © 2011-2022 走看看