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:\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文件爲如下

     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 文件內容 中。

發佈了1 篇原創文章 · 獲贊 2 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章