共享庫編譯extemc
Ⅰ Android 怎麼自定義共享庫
在源碼根目錄下有個 vendor (供應商) 目錄,專門用於存放各個供應商的會有代碼。其中有一個個 sample 目錄,這是 Google 用於示範如何編寫自定義共享庫的示例,它展示了自定義共享庫、JNI 調用、對庫的使用方法及皮膚定製等功能。下面我們通過對該示例進行分析,讓大家熟悉這個輕量級的框架。
1、首先看一下 sample 目錄的結構:
sample
├── Android.mk
├── apps
│ ├── Android.mk
│ ├── client
│ └── upgrade
├── frameworks
│ ├── Android.mk
│ └── PlatformLibrary
├── MODULE_LICENSE_APACHE2
├── procts
│ ├── AndroidProcts.mk
│ └── sample_addon.mk
├── README.txt
├── sdk_addon
│ ├── hardware.ini
│ └── manifest.ini
└── skins
└── WVGAMedDpi
Android.mk: 該文件用於編寫構建規則,默認繼承 Android 的 make 框架。
frameworks: 該目錄在這里的意義等同於 Android 源碼中的 frameworks 。
PlatformLibrary: 該目錄就自定義共享庫。
apps: 該目錄用於編寫依賴該庫的應用程序。經過測試也可以用來編寫不依賴該庫的程序,這有個好處,讓開發商可以把自己特有的應用集成到框架中。
client 與 upgrade: 這是兩個依賴該庫的應用程序示例。
procts: 該目錄中的文件對包含該庫與 Android 框架集成的信息,如模塊名稱等。
AndroidProcts.mk: 指明該模塊的 make 配置文件的在哪裡。
sample_addon.mk :模塊的配置信息。
sdk_addon: 該目錄對該庫的硬體需求進行定義。
hardware.ini: 定義模塊對硬體的需求。
manifest.ini: 模塊的說明文件。名稱、供應商等。
skins: 該目錄用於存放自定義皮膚。
WVGAMedDpi: 已經定義好的一套皮膚。
2.如何封裝 java 共享庫?
PlatformLibrary 為我們展示了封裝 Java 共享庫的方法。其目錄結構如下: frameworks/PlatformLibrary
├── Android.mk
├── com.example.android.platform_library.xml
├── java
│ └── com
│ └── example
│ └── android
│ └── platform_library
│ └── PlatformLibrary.java
└── README.txt
Android.mk: 該文件說明如何構建該模塊。
com.example.android.platform_library.xml: 該文件是模塊注冊時需要的文件。該文件需要被放置到 /system/etc/permissions 目錄下。
Java /*: Java 源碼所在目錄。具體步驟:
a、編寫 Java 庫,並將源碼放到 java 目錄下。這一步和編寫普通 Java 程序沒有差別。
b、編寫 Android.mk,內容如下:
# 獲得當前目錄,清空環境變數
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) # 源碼所在目錄,all-subdir-java-files 表示所有了目錄中的 Java 文件。
LOCAL_SRC_FILES := \
$(call all-subdir-java-files) # 該模塊是可選的。
LOCAL_MODULE_TAGS := optional # Java 模塊名稱
LOCAL_MODULE:= com.example.android.platform_library # 編譯為 Java 庫。最近以 jar 的形式而不是 apk 的形式存在。
include $(BUILD_JAVA_LIBRARY) # 構建該庫的 API 文檔
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-subdir-java-files) $(call all-subdir-html-files)
LOCAL_MODULE:= platform_library
# 文檔對應的庫
LOCAL_DROIDDOC_OPTIONS := com.example.android.platform_library
# 庫的類型
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_DROIDDOC_USE_STANDARD_DOCLET := true # 編譯為 Java API。
include $(BUILD_DROIDDOC)
c、編寫 com.example.android.platform_library.xml,內容如下:
< xml version="1.0" encoding="utf-8" >
<permissions>
<!-- 庫的名稱及對應的 Jar 文件位置 -->
<library name="com.example.android.platform_library"
file="/system/framework/com.example.android.platform_library.jar"/>
</permissions> 現在基本的庫我們已經編寫完成,現在需要對框架中的其它文件進行配置。
d、編寫 sample/frameworks/Android.mk, 內容如下:
# 包含子目錄中的所有 make 文件 include $(call all-subdir-makefiles) 該文件與 sample/Android.mk 文件相同。
e、編寫 sample/sdk_addon/manifest.ini,內容如下: # 該模塊的名稱、供應商及描述
name=Sample Add-On
vendor=Android Open Source Project
description=sample add-on # 構建該模塊的 Android 平台代號
api=3 # 模塊的版本號。必須為整數。
revision=1 # 該模塊中包括的共享庫列表
libraries=com.example.android.platform_library # 對每個庫的詳細定義,格式如下:
# <library.name>=<name>.jar;<desc> # <library.name>: 通過前面 libraies 定義的庫的名稱。
# <name>.jar: 包含庫 API 的 jar 文件。該文件放在 libs/add-on 下面。
com.example.android.platform_library=platform_library.jar;Sample optional plaform library 該文件還可包括該模塊的其它定義,如皮膚等,為了保持該文檔清晰易懂的初衷,這里不做介紹,需要了解可以給我郵件。
f、編寫 sample/procts/sample_addom.mk,內容如下:
# 要植入系統鏡像的應用及可選類庫。可以包括 Java 庫和本地庫。這里我們只有 Java 庫。
PRODUCT_PACKAGES := \ com.example.android.platform_library # 把 xml 文件復制到系統鏡像中相應的位置去。
PRODUCT_COPY_FILES := \ vendor/
sample/frameworks/PlatformLibrary/com.example.android.platform_library.xml:system/etc/permissions/
com.example.android.platform_library.xml # 這個擴展的名稱
PRODUCT_SDK_ADDON_NAME := platform_library # 把模塊的 manifest 和硬體配置文件復制到系統鏡像中相應的位置。 PRODUCT_SDK_ADDON_COPY_FILES := \
vendor/sample/sdk_addon/manifest.ini:manifest.ini \
vendor/sample/sdk_addon/hardware.ini:hardware.in # 把庫的 Jar 包復制到相應的位置。 PRODUCT_SDK_ADDON_COPY_MODULES := \
com.example.android.platform_library:libs/platform_library.jar # 文檔的名稱。必須與。
# LOCAL_MODULE:= platform_library
PRODUCT_SDK_ADDON_DOC_MODULE := platform_library # 這個擴展繼承系統擴展。 $(call inherit-proct, $(SRC_TARGET_DIR)/proct/sdk.mk) # 這個擴展的真實名字。這個名字會用於編譯。
# 用 'make PRODUCT-<PRODUCT_NAME>-sdk_addon' 的形式來編譯此擴展。
PRODUCT_NAME := sample_addon
g、編寫 sample/procts/AndroidProcts.mk,內容如下:
PRODUCT_MAKEFILES := \
$(LOCAL_DIR)/sample_addon.mk h、最後運行make -j8 PRODUCT-sample_addon-sdk_addon,編譯擴展。
至此,我們就完成了 Java 庫的封裝。
3、接下來我們再來看如何通過 JNI 的方式對 C 代碼進行封裝。
a、在 sample/frameworks/PlatformLibrary 目錄下添加一個文件夾,用於放置 JNI 本地代碼,目錄結構如下:
frameworks/PlatformLibrary/jni
├── Android.mk
└── PlatformLibrary.cpp
b、把 frameworks/PlatformLibrary/java/com/example/android/platform_library/PlatformLibrary.java
文件改寫為 JIN 調用介面,代碼如下 : package com.example.android.platform_library; import android.util.Config;
import android.util.Log; public final class PlatformLibrary {
static { / Load the library. If it's already loaded, this does nothing. System.loadLibrary("platform_library_jni");
private int mJniInt = -1; public PlatformLibrary() {} / Test native methods. public int getInt(boolean bad) {
// this alters mJniInt //
int result = getJniInt(bad); // reverse a string, for no very good reason //
String reverse = reverseString("Android!"); Log.i("PlatformLibrary", "getInt: " + result + ", '" + reverse + "'"); return mJniInt; //
/ Simple method, called from native code. private static void yodel(String msg) {
Log.d("PlatformLibrary", "yodel: " + msg); //
/ Trivial native method call. If "bad" is true, this will throw an
/ exception. native private int getJniInt(boolean bad); / Native method that returns a new string that is the reverse of
/ the original. This also calls yodel(). native private static String reverseString(String str);
}
c、在 frameworks/PlatformLibrary/jni/PlatformLibrary.cpp 中編寫 PlatformLibrary.java 中規定本地調用的具體實現。
d、編寫 frameworks/PlatformLibrary/jni/Android.mk,內容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional # JNI 模塊的名稱
LOCAL_MODULE:= libplatform_library_jni # 依賴的源代碼文件
LOCAL_SRC_FILES:= \
PlatformLibrary.cpp # 編譯時需要的庫
LOCAL_SHARED_LIBRARIES := \
libandroid_runtime \
libnativehelper \
libcutils \
libutils # 沒有靜態庫
LOCAL_STATIC_LIBRARIES := # 包含必須的 JNI 頭文件
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) # 編譯器選項
LOCAL_CFLAGS += # 對該模塊不進行預編譯。使用預編譯可以提高模塊的性能。
LOCAL_PRELINK_MODULE := false # 把它編譯成動態共享庫
include $(BUILD_SHARED_LIBRARY) 該文件主要定義了本地庫的名字、依賴、編譯選項及編譯方式。
e、修改 frameworks/PlatformLibrary/Android.mk,在末尾添加如下兩行:
include $(CLEAR_VARS) # 調用子目錄中的 make 文件。
include $(call all-makefiles-under,$(LOCAL_PATH))
f、修改 sdk_addon/sample_addon.mk,在PRODUCT_PACKAGES 中添加該 JNI 本地庫。
PRODUCT_PACKAGES := \
com.example.android.platform_library \
libplatform_library_jni
g、編譯即可。至此,添加 JNI 庫完畢。
4、添加接下來我們再看看如何添加原生應用程序
添加原生應用程序就很簡單了,只需要把按照 Android 應用開發的基本方法,寫好一個應用,該應用可以依賴這個擴展,也可以不依賴。如 sample 中的 client 應用,目錄結構如下: apps/client/
├── AndroidManifest.xml
├── Android.mk
└── src
└── com
└── example
└── android
└── platform_library
└── client
└── Client.java
a、在應用根目錄中添加一個 Android.mk 文件,內容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) LOCAL_MODULE_TAGS := user # 目標名稱
LOCAL_PACKAGE_NAME := PlatformLibraryClient # 只編譯這個apk包中的java文件
LOCAL_SRC_FILES := $(call all-java-files-under, src) # 使用當前版本的 SDK
LOCAL_SDK_VERSION := current # 依賴使用剛才編寫的擴展
LOCAL_JAVA_LIBRARIES := com.example.android.platform_library include $(BUILD_PACKAGE)
b、在 AndroidManifest.xml 中添加一句:
<uses-library android:name="com.example.android.platform_library" />
c、修改 sdk_addon/sample_addon.mk,在PRODUCT_PACKAGES 中添加該 JNI 本地庫。
PRODUCT_PACKAGES := \
com.example.android.platform_library \
libplatform_library_jni \
PlatformLibraryClient
d、編譯即可。至此,添加 JNI 庫完畢。
5、其他功能如添加皮膚等,這里就不一一示範了,請參考<sdk-src>/vendor/sample。
Ⅱ 關於使用QLibrary如何讀取共享庫
現在程序講究個模塊化,插件化,所有共享庫的讀取變的尤其關鍵,把程序寫成各種各樣的共享庫,那升級的時候只需要重寫下某個庫,在保證頭文件不變的情況下,更新上去,就能完美運行。Qt中讀取使用共享庫的類叫QLibrary. 使用起來也相當簡單,最基本的使用只需要知道4個函數,load(), isLoad(), revovle()和unload().在絕大部分情況下,下面這四個函數就足夠完成工作了。下面是個小例子:
// 庫名是mylib.so,這個文件後綴可以不加
// Qt會根據操作系統自動添加後綴
QLibrary lib(mylib);
// 這是最重要的地方,根據你要調用的庫函數先定義一個相同的函數指針
typedef (MyType *)(InstanceOf)();
// instanceOf是你要讀取的庫中的函數名字
InstanceOf instance = (InstanceOf)lib.revolve(instanceOf);
// revolve成功則運行函數
// 不成功則輸出錯誤字元串
if(instance)
MyType *ret = instance();elseqDebug() << lib.errorString();
這里並沒有使用到load()函數,這是因為revolve()函數會自動去載入庫,同時Qt還給出了一個簡單的static函數來讀取庫中的函數:
typedef (MyType *)(InstanceOf)();
InstanceOf instance = QLibrary::revolve(mylib,instanceOf);
if(instance)
MyType *ret = instance();
最後要著重說明的就是,QLibrary只能讀取共享庫內的C函數,這是因為C++為了達到面向對象編程封裝,繼承,多態等特性,實際的symbol table和你定義的是不同的,他會在編譯過程中加入一些字元,比如上例中的instanceOf函數,在symbol table中可能是_ZV12instanceOf4FR這樣的存在,所以如果把該函數聲明為簡單的類函數,QLibrary是找不到的,必須要將你准備讓QLibrary讀的函數聲明為C函數,如下
extern C MyType *instanceOf(){return new MyType();}這個函數返回MyType的一個對象,這樣,只要你有相應的頭文件,就可以完全使用這個對象內的其他類函數了。
Ⅲ Linux下的動態共享鏈接庫的優點有哪些
動態共享庫有以下的優點,使它在Linux開發中比靜態鏈接庫更加的流行。
(1) 節省內存
動態共享庫無論被多少應用程序使用,在內存中都只存在一個動態共享庫的副本,而不像靜態鏈接庫那樣,一個應用程序在運行中用到靜態鏈
接庫,就會有多個靜態鏈接庫的副本 。
(2) 節省磁碟
這和節省內存有點相似,同樣這也是由於靜態鏈接庫存在多個靜態鏈接庫的副本造成的。同樣的應用程序,使用動態共享庫編譯出的版本通常比使用靜態鏈接庫編譯出來的版本要小。因此,在嵌入式系統開發中使用動態共享庫也不節省空間,提供了一種很好的選擇。
(3) 便於軟體修復與升級
由於動態共享是獨立於應用程序存在的,因此,用新版本的動態共享庫替舊版本的工作將變得非常容易。如果使用靜態鏈接庫的話,假設在一個靜態庫中發現了一個
ug,那麼要修正這個
ug的話,就要重新編譯所有使用這個靜態庫的應用程序,使用這個靜態庫的應用程序有很多的話,可以想像工作量是有多大。
(4) 提高性能
與採用靜態鏈接庫臃腫的應用程序相比,採用動態共享庫的應用程序明顯「苗條」得多,這樣當操作系統載入應用程序時,是需要把應用程序
復制到內存中的,這樣的「苗條」的動態鏈接庫也就有了很大的優勢,同時提高了程序的性能。
當然,動態鏈接庫在有上述這些優勢的同時,也有以下的幾個劣勢。復雜性,兼容性,調試困難。但是它在Linux上使用頻率上仍然比靜態鏈接庫要高的多。應用的更加廣泛。
Ⅳ Android中靜態庫和共享庫的區別
簡單來講:
靜態庫是在連接階段直接拷貝到代碼中使用的,而共享庫是由載入器載入到內存,在運行時使用的。
編譯出來的靜態庫(這里指jar包)里每個java文件對應的class文件都單獨存在,可以直接導入Eclipse等IDE使用
而編譯出來的共享庫(jar包),內部是Android位元組碼Dex格式的文件,一般無法導入Eclipse等IDE使用。Android.mk中由BUILD_JAVA_LIBRARY指定生成共享BUILD_STATIC_JAVA_LIBRARY指定生成靜態庫。
Ⅳ android.mk ubuntu怎麼編譯
一個Android.mk file用來向編譯系統描述你的源代碼。具體來說:該文件是GNU Makefile的一小部分,會被編譯系統解析一次或多次。你可以在每一個Android.mk file中定義一個或多個模塊。每個模塊屬下列類型之一:
1)APK程序,一般的Android程序,編譯打包生成apk文件
2)Java庫,java類庫,編譯打包生成jar文件
3) CC++應用程序,可執行的CC++應用程序
4)CC++靜態庫,編譯生成CC++靜態庫,並打包成.a文件
5)CC++共享庫,編譯生成共享庫(動態鏈接庫),並打包成.so, 有且只有共享庫才能被安裝/復制到您的應用軟體(APK)包中。
(1)先看一個簡單的例子:一個簡單的"hello world",比如下面的文件:
sources/helloworld/helloworld.c
sources/helloworld/Android.mk
相應的Android.mk文件會像下面這樣:
---------- cut here ------------------
普通的.mk一樣
=====================================m、mm、mmm編譯命令===========================================
android源碼目錄下的build/envsetup.sh文件,描述編譯的命令
- m: Makes from the top of the tree.
- mm: Builds all of the moles in the current directory.
- mmm: Builds all of the moles in the supplied directories.
所以要想使用這些命令,首先需要在android源碼根目錄執行build/envsetup.sh 腳本設置環境。
m:編譯所有的模塊
mm:編譯當前目錄下的模塊,當前目錄下要有Android.mk文件
mmm:編譯指定路徑下的模塊,指定路徑下要有Android.mk文件
下面舉個例子說明,假設我要編譯android下的hardwarelibhardware_legacypower模塊,當前目錄為源碼根目錄,方法如下:
1、. build/envsetup.sh
2、mmm hardware/libhardware_legacy/power/
或者 :
1、. build/envsetup.sh
2、cd hardware/libhardware_legacy/power/
3、mm
m沒有試過。默認上述兩個編譯命令,只編譯發生變化的文件。如果要編譯模塊的所有文件,需要-b選項,例如mm -b或者mmm -b
make命令,也可以用來編譯。如果是include $(BUILD_PACKAGE),用makeLOCAL_PACKAGE_NAME值;如果是include $(BUILD_EXECUTABLE)或者include $(BUILD_JAVA_LIBRARY),用makeLOCAL_MODULE值(未驗證)。
Ⅵ 程序開發中庫的作用
所謂庫就是「程序庫」,包含了一些通用函數的數據和二進制可執行機器碼的文件。這些文件是目標文件的一種,其不能單獨執行。但是如果將其與其他的可執行程序結合起來就可以執行了。這些目標文件通常可以完成同一類功能,它們可以作為其他執行程序的一部分來執行。由於庫的存在,使得用戶編寫的程序模塊化更強,從而可以加快程序的再編譯,提高代碼的復用性,同時也使程序更加易於升級和管理。對於讀取文件內容,將大寫字母轉換為小寫字母的簡單程序來說,其程序的構成可以分為兩個相對獨立的模塊,一個模塊負責從外部設備上讀入文件,一個模塊負責將文件內容進行適當的轉換。這兩個模塊分工明確,互相不需要了解對方的細節。當需要將程序升級為將小寫字母轉換為大寫字母時,不需要改變第一個讀入文件的模塊,只需更新負責轉換操作的模塊就可以了。使用一個將小寫字母轉換為大寫字母替換原來的轉換處理模塊,這時程序就完成了更新。假設現在需要生成一個讀入文件內容,將文件中的多個空格合並為一個空格的程序時,就用不著重新生成一個文件讀入模塊,而直接使用第一個程序的文件讀入模塊就可以了。從鏈接方式上區分,程序庫可分靜態庫和動態庫(共享庫)兩種:
靜態庫:是在可執行程序運行前就已經加入到執行碼中,成為執行程序的一部分來執行的。
共享庫:是在執行程序啟動時載入到執行程序中,可以被多個執行程序共享使用。
Ⅶ 如何在C++中使用共享庫的動態載入
一、先看看測試程序
1.庫部分
hello.h
[cpp] view plain
在CODE上查看代碼片派生到我的代碼片
#ifndef ANDROID_Hello_H
#define ANDROID_Hello_H
class Hello_Base
{
public:
virtual ~Hello_Base() {};
virtual int setctl(int ctl) = 0;
virtual int getctl(int ctl) = 0;
};
class Hello : public virtual Hello_Base
{
public:
virtual ~Hello() {};
static Hello* Instance();
int setctl(int ctl);
int getctl(int ctl);
private:
static Hello* _instance;
int myctl;
};
extern "C" Hello_Base* CreatHello();
typedef Hello_Base* CreatHelloClass();
#endif
hello.cpp
[cpp] view plain
在CODE上查看代碼片派生到我的代碼片
#include "hello.h"
#include <stdio.h>
extern "C" Hello_Base* CreatHello(){
return Hello::Instance();
}
Hello* Hello::_instance = 0;
Hello* Hello::Instance()
{
printf("TK------>>>>>>Hello::Instance---------\n");
if(_instance == 0){
_instance = new Hello();
}
return _instance;
}
int Hello::setctl(int ctl)
{
printf("TK------->>>>>>setctl-----\n");
this->myctl = ctl;
return 1;
}
int Hello::getctl(int ctl)
{
printf("TK------->>>>>>getctl-----\n");
return this->myctl;
}
編譯成動態鏈接庫,一般要求PIC位置無關:
g++ -shared -fPIC -o libhello.so hello.cpp
生成:libhello.so
2.測試用例
test.cpp
[cpp] view plain
在CODE上查看代碼片派生到我的代碼片
#include "so/hello.h"
#include <stdio.h>
#include <dlfcn.h>
int main()
{
void* hello = dlopen("/home/lianxi/c++/ku/so/libhello.so", RTLD_LAZY);
if(!hello){
printf("dlopen /home/lianxi/c++/ku/so/libhello.so error!\n");
return -1;
}
dlerror();
CreatHelloClass* Creat_Hello = (CreatHelloClass*)dlsym(hello,"CreatHello");
const char* dlsym_error = dlerror();
if (dlsym_error) {
printf("error %s\n",dlsym_error);
return -1;
}
Hello_Base* mHello = Creat_Hello();
mHello->setctl(5);
int result = mHello->getctl(0);
printf("TK------>>>>>result is %d\n",result);
dlclose(hello);
return 1;
}
編譯:g++ -o test test.cpp -L. -ldl
執行./test結果:
[plain] view plain
在CODE上查看代碼片派生到我的代碼片
TK------>>>>>>Hello::Instance---------
TK------->>>>>>setctl-----
TK------->>>>>>getctl-----
TK------>>>>>result is 5
二、分析
1.libdl庫為C語言開發,當需要在C++中dlsym某個符號時、需要聲明庫中該符號為extern 「C」,比如例子中的extern "C" Hello_Base* CreatHello();
2.由於不可能像C語言那樣將C++類中的那麼多方法都dlsym出來,這里使用了C++中對於純虛類的實例化是運行時鏈接的特點;也就是說要在C++中對於類使用共享庫的動態鏈接、必須定義一個純虛的子類。
Ⅷ Android 怎麼自定義共享庫
LOCAL_PATH := $(call my-dir)//標准mk語句,指編譯路徑,所有mk文件第一句都是這個 /**這個模塊表示引用了一個本地的靜態庫 include $(CLEAR_VARS) //清除各種變數,因為這些變數是靜態全局的,如果清除,下次編譯時又會用到這些變數造成出錯 LOCAL_MODULE := libopencore-amrnb //本地靜態庫模塊的名字,這個名字在下面編譯jni時需要引用 LOCAL_SRC_FILES := lib/libopencore-amrnb/smfwuxiao/article/details/6591927 NDK r5 開始支持預編譯共享庫。預編譯共享庫就是從其他地方獲得源碼編譯出的共享庫,而不是Android系統自帶的。方法如下: 1、聲明共享庫模塊 把共享庫聲明為一個獨立模塊。假如 libfoo.so 與 Android.mk 位於同一目錄。則 Android.mk 應該這樣寫: LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := foo-prebuilt # 模塊名 LOCAL_SRC_FILES := libfoo.so # 模塊的文件路徑(相對於 LOCAL_PATH) include $(PREBUILT_SHARED_LIBRARY) # 注意這里不是 BUILD_SHARED_LIBRARY 這個共享庫將被拷貝到 $PROJECT/obj/local 和 $PROJECT/libs/<abi> (strip過的) 2、在其他模塊中引用這個共享庫 在 Android.mk 中,將這個共享庫的模塊名加入 LOCAL_STATIC_LIBRARIES (靜態庫)或 LOCAL_SHARED_LIBRARIES (動態庫) 例如, 使用 libfoo.so 的方法: include $(CLEAR_VARS) LOCAL_MODULE := foo-user LOCAL_SRC_FILES := foo-user.c LOCAL_SHARED_LIBRARY := foo-prebuilt include $(BUILD_SHARED_LIBRARY) 3、為共享庫導出頭文件 這個共享庫一般有相應的頭文件,比如 libfoo.so 就有 foo.h。 一個簡單方法(在Android.mk中寫): include $(CLEAR_VARS) LOCAL_MODULE := foo-prebuilt LOCAL_SRC_FILES := libfoo.so LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include include $(PREBUILT_SHARED_LIBRARY) 這樣,使用該共享庫的模塊就會在它的 LOCAL_C_INCLUDES 變數加入該頭文件搜索路徑。 4、調試共享庫 建議你的共享庫保留調試信息。 $PROJECT/libs/<abi> 目錄下的共享庫都是 strip 之後的(沒有調試信息)。有調試信息的版本可被ndk-gdb使用。 5、共享庫 ABI 你的共享庫與目標系統ABI的兼容性很重要。 請檢查 TARGET_ARCH_ABI,有以下值: armeabi => ARMv5TE 以上 armeabi-v7a => ARMv7 以上 x86 => x86 建議: armeabi ABI 可以運行在所有 ARM CPU 上。