編譯動態庫如何指定包含的庫
1. 如何編譯&使用boost庫
1. 編譯
1.2. VS2005編譯boost_1_55_0
1.2.1. 使用vs2005的命令行執行:...\boost_1_55_0\bootstrap.bat
1.2.2. 編譯動態庫
bjam install stage --toolset=msvc-8.0 --stagedir="C:\Boost\boost_vc_80" link=shared runtime-link=shared threading=multi debug release
1.2.3. 編譯靜態庫
bjam install stage --toolset=msvc-8.0 --stagedir="D:\Boost\boost_vc_80" link=static runtime-link=static threading=multi debug release
各種參數詳解:
stage:表示只生成庫(dll和lib)
install:還會生出包含的頭文件
--toolset=msvc-8.0:指定編譯器版本,8.0為vs2005,其他VS類推。
--stagedir:指定編譯後存放的目錄
link:生成動態庫/靜態庫。動態庫(shared),靜態庫(static)
runtime-link:動態/靜態C/C++運行時庫,同樣有shared和static兩種組合方式。這樣共有4種組合方式,個人根據自己需要選擇。
threading:單/多線程,一般都是多線程程序,當然multi了。
debug/release:編譯版本,一般2個都需要。
2. 使用
使用靜態庫:
[cpp] view plain print?
//#define BOOST_ALL_DYN_LINK
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
使用靜態庫連接時,僅需要包含的lib為:
debug版:libboost_system-vc80-mt-gd-1_55.lib等一系列包含gd的庫。
release版本:libboost_system-vc80-mt-1_55.lib等一系列不包含gd的庫。
使用動態庫鏈接:
[cpp] view plain print?
#define BOOST_ALL_DYN_LINK
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
使用動態庫鏈接時,僅需要包含的lib為:
debug版:boost_system-vc80-mt-gd-1_55.lib,同時在生成的exe加入boost_system-vc80-mt-gd-1_55.dll
release版:boost_system-vc80-mt-1_55.lib,同時在生產的exe路徑下加入boost_system-vc80-mt-1_55.dll
2. 指定一些庫使用靜態的某些使用動態的嗎
C語言中有一些函數不需要進行編譯,有一些函數也可以在多個文件中使用。一般來說,這些函數都會執行一些標准任務,如資料庫輸入/輸出操作或屏幕控
制等。可以事先對這些函數進行編譯,然後將它們放置在一些特殊的目標代碼文件中,這些目標代碼文件就稱為庫。庫文件中的函數可以通過連接程序與應用程序進
行連接。這樣就不必在每次開發程序時都對這些通用的函數進行編譯了。
不同類型的應用程序將會使用不同的函數庫。例如:libdbm
庫中組包含了對資料庫文件進行訪問的dbm函數,需要對資料庫進行操作的程序就會與該庫進行連接。數學應用程序將使用數學庫libm,X-Windows
應用程序將使用Xlib庫,libX11。另外,所有的程序都將使用標準的C函數庫。libc,該庫中包含了諸好內存管理或輸入輸出操作的基本函數,這些
庫都存放在/usr/lib這些系統公用的目錄
中,系統中的任何用戶都可以利用這些庫。當然用戶也可以建立自己專用的庫函數,供自己或其它指定的人員使用。
庫可以有三種使
用的形式:靜態、共享和動態。靜態庫的代碼在編譯時就已連接到開發人員開發的應用程序中,而共享庫只是在程序開始運行時才載入,在編譯時,只是簡單地指定
需要使用的庫函數。動態庫則是共享庫的另一種變化形式。動態庫也是在程序運行時載入,但與共享庫不同的是,使用的庫函數不是在程序運行開始,而是在程序中
的語句需要使用該函數時才載入。動態庫可以在程序運行期間釋放動態庫所佔用的內存,騰出空間供其它程序使用。由於共享庫和動態庫並沒有在程序中包括庫函數
的內容,只是包含了對庫函數的引用,因此代碼的規模比較小。
已經開發的大多數庫都採取共享庫的方式。ELF格式的可執行文件使得共享庫能夠比較容易地實現,當然使用舊的a.out模式也可以實現庫的共享。Linux系統中目前可執行文件的標准格式為ELF格式。
GNU庫的使用必須遵守Library GNU Public License(LGPL許可協議)。該協議與GNU許可協議略有不同,開發人員可以免費使用GNU庫進行軟體開發,但必須保證向用戶提供所用的庫函數的源代碼。
系統中可用的庫都存放在/usr/lib和/lib目錄中。庫文件名由前綴lib和庫名以及後綴組成。根據庫的類型不同,後綴名也不一樣。共享庫的後綴名由.so和版本號組成,靜態庫的後綴名為.a。採用舊的a.out格式的共享庫的後綴名為.sa。
libname.so.major.minor
libname.a
這里的name可以是任何字元串,用來唯一標識某個庫。該字元串可以是一個單字、幾個字元、甚至一個字母。數學共享庫的庫名為libm.so.5,這里
的標識字元為m,版本號為5。libm.a則是靜態數學庫。X-Windows庫名為libX11.so.6,這里使用X11作為庫的標識,版本號為6。
使用gcc編譯器就可以將庫與自己開發的程序連接起來,例如:libc.so.5中包含了標準的輸入輸出函數,當連接程序進行目標
代碼連接時會自動搜索該程序並將其連接到生成的可執行文件中。標準的輸入輸出庫中包含了許多基本的輸入輸出函數,如printf函數等。也可以連接其它的
一些系統函數庫,如數學庫等,但與libc.so.5不同,大部分其它的系統庫需要在命令行中顯式指定所用的庫名。
在/usr
/lib和/lib目錄中可以找到絕大多數的共享庫。連接時將首先搜索這兩個目錄。有一些庫也可能存放在特定的目錄中,在/etc/ld.conf配置文
件中給出了這些目錄的列表。連接程序也會對列出的這些目錄進行搜索。在默認情況下,Linux將首先搜索指定庫的共享版本,如果找不到,才會去搜索靜態版
本。在對共享庫進行更新或安裝新庫後,必須運行ldconfig命令更新/etc/ld.conf文件中相應的項(如果使用RPM進行安裝,一般會自動進
行更新,不過也不能保證這一點)。
在gcc編譯器中引用可搜索到的目錄中的庫文件時,需要使用-l選項和庫名。在gcc命令行上輸
入-lm可以在程序中連接標准算術庫,-l將首先使用libname.so進行搜索,這里是libm.so。下面的例子將使用算術庫創建bookrecs
程序,請注意這里的-lm選項。
$ gcc main.c io.c -o bookrecs -lm
系統中還有一些其它可用的庫,常用的是libncurses.a庫,包含了一些簡單的滑鼠移動常式。在命令行中使用-lncurses選項引用libncurses.so庫。下面的例子同時調用了數學和游標庫。
$ gcc mian.c io.c -o bookrecs -lm -lncurses
在引用其它目錄中的庫時,需要使用-ldir選項指定該目錄。該選項指定了搜索庫函數時其它路徑。在下面的例子中,用戶在連接時使用了mydir目錄中的myio.so庫文件。
$ gcc main.c -o bookrecs -lmydir -lmyio
.a的是為了支持較老的a.out格式的可執行文件的
.so的是支持elf格式的可執行文件的庫。
靜態庫是指編譯連接時,把庫文件的代碼全部加入到可執行文件中,所以生成的文件較大, 但運行時,就不再需要庫文件了。動態庫正好相反,在編譯連接時,沒有把庫文件的代碼加入到可執行文件中,所以生成的文件較小,但運行時,仍需要載入庫文件
.a是靜態庫文件,可以用ar 命令生成。
.so是動態庫文件,編譯時加上指定的選項即可生成,具體選項看相應的系統文檔了。。。。
IBM AIX下如下:
$(CC) $(SHOPT) $(SHLIBS) a.o b.o -o lib$@$(DBBUILDTAIL)
假設你有test1.c test2.c test3.c , 編寫成動態鏈接庫
1. 先編譯成test1.o test2.o test3.o
2. gcc -shared -W1, -soname,libvTest.so.1 -o libvTest.so.1.0 *.o
3. 如何編譯動態庫,該動態庫需要鏈接另外一個動態庫
看你的makefile, 猜測是沒有指定動態庫頭文件的路徑. -I編譯參數來指定
4. 請教,如何讓Gcc編譯生成的動態庫,包含符號表
item表示迭代的參數 比如你的這個數組通過request.setAttribute("array",xxx)放入了這個里,迭代的內容就是${requestScope.array}
var 相當於一個引用
下面你就可以用
${array.xxx1}
${array.xxx2}
將數組里的值輸出出來了
5. ndk-Android NDk 怎麼編譯時動態鏈接第三方so庫,有頭文件
問題描述:Android如何調用第三方SO庫;
已知條件:SO庫為Android版本連接庫(*.so文件),並提供了詳細的介面說明;
已了解解決方案:
1.將SO文件直接放到libs/armeabi下,然後代碼中System.loadLibrary("xxx");再public native static int xxx_xxx_xxx();接下來就可以直接調用xxx_xxx_xxx()方法;
2.第二種方案,創建自己的SO文件,在自己的SO文件里調用第三方SO,再在程序中調用自己的SO,這種比較復雜,需要建java類文件,生成.h文件,編寫C源文件include之前生成的.h文件並實現相應方法,最後用android NDK開發包中的ndk-build腳本生成對應的.so共享庫;
求解:
1.上面兩種方案是否可行?不可行的話存在什麼問題?
2.兩種方案有什麼區別?為什麼網上大部都是用的第二種方案?
3.只有一個*.so文件,並提供了詳細的介面說明,是否可在ANDROID中使用它?
首先要看這個SO是不是JNI規范的SO,比如有沒有返回JNI不直接支持的類型。也就是說這個SO是不是可以直接當作JNI來調用。如果答案是否定的,你只能選第二個方案。
如果答案是肯定的,還要看你是不是希望這個SO的庫直接暴露給JAVA層,如果答案是否定的,你只能選第二個方案,比如你本身也是一個庫的提供者。
一般如果你只有SO,就說明這個是別人提供給你的,你可以要求對方給你提供配套的JAVA調用文件。
1、這個要看這個SO是不是符合JNI調用的規范。還要看你自己的意願。
2、因為第二種方法最靈活,各種情況都可以實現。
3、可以
看能不能直接從JAVA調用的最簡單的方法就是看SO里的函數名是不是Java_XXX_XXX_XXX格式的
是就可以,你可以自己寫一個配套的JAVA文件,注意一下SO函數名和JAVA函數名的轉換規則,或者向SO提供方索要;
不是的話就選第二種方案吧。
1、檢查所需文件是否齊全
使用第三方動態庫,應該至少有2個文件,一個是動態庫(.so),另一個是包含
動態庫API聲明的頭文件(.h)
2、封裝原動態庫
原動態庫文件不包含jni介面需要的信息,所以我們需要對其進行封裝,所以我
們的需求是:將libadd.so 裡面的API封裝成帶jni介面的動態
3、編寫庫的封裝函數libaddjni.c
根據前面生成的com_android_libjni_LibJavaHeader.h 文件,編寫libaddjni.c,用
來生成libaddjni.so
Android中集成第三方軟體包(.jar, .so)
Android中可能會用到第三方的軟體包,這包括Java包.jar和Native包.so。jar包既可通過Eclipse開發環境集成,也可通過編譯源碼集成,看你的工作環境。
假定自己開發的程序為MyMaps,需要用到BaiMaps的庫,包括mapapi.jar和libBMapApiEngine_v1_3_1.so。
一、Eclipse中集成第三方jar包及.so動態庫
MyMaps工程下創建目錄libs以及libs/armeabi,把mapapi.jar放在的libs/目錄下,把libBMapApiEngine_v1_3_1.so放在libs/armeabi/下。
Eclipse中把第三方jar包mapapi.jar打包到MyMaps的步驟:
1. 右擊工程,選擇Properties;
2. Java Build Path,選擇Libraries;
3. Libraries頁面點擊右面按鈕「Add Library…」;
4. 選擇「User Library」,點擊「Next」;
5. 點擊「User Libraries」按鈕;
6. 在彈出界面中,點擊「New…」;
7. 輸入「User library name」,點擊「OK」確認;
8. 返回之後,選擇剛剛創建的User library,右面點擊「AddJARs」;
9. 選擇MyMaps/libs/下的mapapi.jar;
10. 確認,返回。
這樣,編譯之後,該jar包就會被打進MyMaps.apk中,libBMapApiEngine_v1_3_1.so也被打包在lib/armeabi/中。
程序運行過程中,libBMapApiEngine_v1_3_1.so被放在/data/data/<yourAppPackage>/lib/下,載入動態庫時系統會從程序的該lib/目錄下查找.so庫。
二、源碼中集成第三方集成jar包及.so動態庫
Android源碼中MyMaps放在packages/apps下。MyMaps下創建目錄libs以及libs/armeabi,並把mapapi.jar放在libs/,把libBMapApiEngine_v1_3_1.so放在libs/armeabi。
2.1 修改Android.mk文件
Android.mk文件如下:
[plain] view plain
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := libmapapi
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := MyMaps
include $(BUILD_PACKAGE)
##################################################
include $(CLEAR_VARS)
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES :=libmapapi:libs/mapapi.jar
LOCAL_PREBUILT_LIBS :=libBMapApiEngine_v1_3_1:libs/armeabi/libBMapApiEngine_v1_3_1.so
LOCAL_MODULE_TAGS := optional
include $(BUILD_MULTI_PREBUILT)
# Use the following include to make our testapk.
include $(callall-makefiles-under,$(LOCAL_PATH))
1 集成jar包
LOCAL_STATIC_JAVA_LIBRARIES取jar庫的別名,可以任意取值;
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES指定prebuiltjar庫的規則,格式:別名:jar文件路徑。注意:別名一定要與LOCAL_STATIC_JAVA_LIBRARIES里所取的別名一致,且不含.jar;jar文件路徑一定要是真實的存放第三方jar包的路徑。
編譯用BUILD_MULTI_PREBUILT。
2 集成.so動態庫
LOCAL_PREBUILT_LIBS指定prebuilt so的規則,格式:別名:so文件路徑。注意:別名一般不可改變,特別是第三方jar包使用.so庫的情況,且不含.so;so文件路徑一定要是真實的存放第三方so文件的路徑。
編譯拷貝用BUILD_MULTI_PREBUILT。
2.2 加入到GRANDFATHERED_USER_MODULES
在文件user_tags.mk中,把libBMapApiEngine_v1_3_1加入到GRANDFATHERED_USER_MODULES中
[plain] view plain
GRANDFATHERED_USER_MODULES += \
… \
libBMapApiEngine_v1_3_1
user_tags.mk可以是build/core下的,也可以是$(TARGET_DEVICE_DIR)下的,推薦修改$(TARGET_DEVICE_DIR)下的。
2.3 編譯結果
MyMaps.apk編譯生成在out/target/proct/<YourProct>/system/app/下;
libBMapApiEngine_v1_3_1.so放在out/target/proct/<YourProct>/system/lib/下,這也是系統載入動態庫時搜索的路徑。
6. 如何用gcc編譯動態庫
今天要用到靜態庫和動態庫,於是寫了幾個例子來鞏固一下基礎。
hello1.c ————————————————————
#include <stdio.h>
void print1(int i) { int j; for(j=0;j<i;j++) { printf("%d * %d = %d\n",j,j,j*j); } }
hello2.c _________________________________________________
#include <stdio.h>
void print2(char *arr) { char c; int i=0; while((c=arr[i++])!='\0') { printf("%d****%c\n",i,c); } }
hello.c ____________________________________________________
void print1(int); void print2(char *);
int main(int argc,char **argv) { int i=100; char *arr="THIS IS LAYMU'S HOME!"; print1(i); print2(arr);
return 0; }
可以看到hello.c要用到hello1.c中的print1函數和hello2.c中的print2函數。所以可以把這兩個函數組合為庫,以供更多的程序作為組件來調用。
方法一:將hello1.c和hello2.c編譯成靜態鏈接庫.a
[root@localhost main5]#gcc -c hello1.c hello2.c
//將hello1.c和hello2.c分別編譯為hello1.o和hello2.o,其中-c選項意為只編譯不鏈接。
[root@localhost main5]#ar -r libhello.a hello1.o hello2.o
//將hello1.o和hello2.o組合為libhello.a這個靜態鏈接庫
[root@localhost main5]#cp libhello.a /usr/lib
//將libhello.a拷貝到/usr/lib目錄下,作為一個系統共享的靜態鏈接庫
[root@localhost main5]#gcc -o hello hello.c -lhello
//將hello.c編譯為可執行程序hello,這個過程用到了-lhello選項,這個選項告訴gcc編譯器到/usr/lib目錄下去找libhello.a的靜態鏈接庫
以上的過程類似於windows下的lib靜態鏈接庫的編譯及調用過程。
方法二:將hello1.o和hello2.o組合成動態鏈接庫.so
[root@localhost main5]#gcc -c -fpic hello1.c hello2.c
//將hello1.c和hello2.c編譯成hello1.o和hello2.o,-c意為只編譯不鏈接,-fpic意為位置獨立代碼,指示編譯程序生成的代碼要適合共享庫的內容這樣的代碼能夠根據載入內存的位置計算內部地址。
[root@localhost main5]#gcc -shared hello1.o hello2.o -o hello.so
//將hello1.o和hello2.o組合為shared object,即動態鏈接庫
[root@localhost main5]#cp hello.so /usr/lib
//將hello.so拷貝到/usr/lib目錄下
[root@localhost main5]#gcc -o hello hello.c hello.so
//將hello.c編譯鏈接為hello的可執行程序,這個過程用到了動態鏈接庫hello.so
在這里要廢話幾句,其實一切的二進制信息都有其運作的機制,只要弄清楚了它的機制,並能夠實現之,則任何此時此刻無法想像之事都將成為現實。當然,這兩者之間的巨大鴻溝需要頂級的設計思想和頂級的代碼來跨越。
7. g++ 編譯命令中依賴的動態庫如果還依賴別的庫,命令怎麼設置
第一步,我先從簡單的調用出發,定義了一個簡單的函數,該函數僅僅實現一個整數加法求和:
LIBEXPORT_API int mySum(int a,int b){ return a+b;}
C# 導入定義:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
public static extern int mySum (int a,int b);
}
在C#中調用測試:
int iSum = RefComm.mySum(,);
運行查看結果iSum為5,調用正確。第一步試驗完成,說明在C#中能夠調用自定義的動態鏈接庫函數。
第二步,我定義了字元串操作的函數(簡單起見,還是採用前面的函數名),返回結果為字元串:
LIBEXPORT_API char *mySum(char *a,char *b){sprintf(b,"%s",a); return a;}
C# 導入定義:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Auto,
CallingConvention=CallingConvention.StdCall)]
public static extern string mySum (string a, string b);
}
在C#中調用測試:
string strDest="";
string strTmp= RefComm.mySum("45", strDest);
運行查看結果 strTmp 為"45",但是strDest為空。我修改動態鏈接庫實現,返回結果為串b:
LIBEXPORT_API char *mySum(char *a,char *b){sprintf(b,"%s",a) return b;}
修改 C# 導入定義,將串b修改為ref方式:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
public static extern string mySum (string a, ref string b);
}
在C#中再調用測試:
string strDest="";
string strTmp= RefComm.mySum("45", ref strDest);
運行查看結果 strTmp 和 strDest 均不對,含不可見字元。再修改 C# 導入定義,將CharSet從Auto修改為Ansi:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]
public static extern string mySum (string a, string b);
}
在C#中再調用測試:
string strDest="";
string strTmp= RefComm. mySum("45", ref strDest);
運行查看結果 strTmp 為"45",但是串 strDest 沒有賦值。第二步實現函數返回串,但是在函數出口參數中沒能進行輸出。再次修改 C# 導入定義,將串b修改為引用(ref):
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]
public static extern string mySum (string a, ref string b);
}
運行時調用失敗,不能繼續執行。
第三步,修改動態鏈接庫實現,將b修改為雙重指針:
LIBEXPORT_API char *mySum(char *a,char **b){sprintf((*b),"%s",a); return *b;}
C#導入定義:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]
public static extern string mySum (string a, ref string b);
}
在C#中調用測試:
string strDest="";
string strTmp= RefComm. mySum("45", ref strDest);
運行查看結果 strTmp 和 strDest 均為"45",調用正確。第三步實現了函數出口參數正確輸出結果。
第四步,修改動態鏈接庫實現,實現整數參數的輸出:
LIBEXPORT_API int mySum(int a,int b,int *c){ *c=a+b; return *c;}
C#導入的定義:
public class RefComm
{
[DllImport("LibEncrypt.dll",
EntryPoint=" mySum ",
CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]
public static extern int mySum (int a, int b,ref int c);
}
在C#中調用測試:
int c=0;
int iSum= RefComm. mySum(,, ref c);
運行查看結果iSum 和c均為5,調用正確。
經過以上幾個步驟的試驗,基本掌握了如何定義動態庫函數以及如何在 C# 定義導入,有此基礎,很快我實現了變長加密函數在 C# 中的調用,至此目標實現。
三、結論
在 C# 中調用 C++ 編寫的動態鏈接庫函數,如果需要出口參數輸出,則需要使用指針,對於字元串,則需要使用雙重指針,對於 C# 的導入定義,則需要使用引用(ref)定義。
對於函數返回值,C# 導入定義和 C++ 動態庫函數聲明定義需要保持一致,否則會出現函數調用失敗。定義導入時,一定注意 CharSet 和 CallingConvention 參數,否則導致調用失敗或結果異常。運行時,動態鏈接庫放在 C# 程序的目錄下即可,我這里是一個 C# 的動態鏈接庫,兩個動態鏈接庫就在同一個目錄下運行。
8. android已有動態庫怎麼編譯靜態庫
在eclipse工程目錄下建立一個jni的文件夾
在jni文件夾中建立Android.mk和Application.mk文件
Android.mk文件:
Android提供的一種makefile文件,用來指定諸如編譯生成so庫名、引用的頭文件目錄、需要編譯的.c/.cpp文件和.a靜態庫文件等。詳見附件中的Android.mk。
Application.mk文件:
定義了項目的一些細節,比如APP_ABI := x86(編譯X86平台庫)、APP_PLATFORM := android-9(使用android-9以上的平台庫)。
NDK 編譯和使用靜態庫、動態庫
情況一:編譯靜態庫
情況二:編譯動態庫
情況三:編譯動態庫+靜態庫
情況四:已有第三方靜態庫(動態庫),編譯靜態庫(動態庫)
默認所有代碼和文件在$project/jni下,否則特殊說明。
情況一:編譯靜態庫
文件Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_STATIC_LIBRARY)
文件Application.mk:
APP_MODULES :=hello-jni
情況二:編譯動態庫
文件Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
情況三:編譯動態庫+靜態庫
文件Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mylib_static
LOCAL_SRC_FILES := src.c
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := mylib_shared
LOCAL_SRC_FILES := src2.c
LOCAL_STATIC_LIBRARIES := mylib_static
include $(BUILD_SHARED_LIBRARY)
情況四:已有第三方靜態庫(動態庫),編譯靜態庫(動態庫)
文件Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := thirdlib1 # name it whatever
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libthird1.a # or $(so_path)/libthird1.so
#LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_STATIC_LIBRARY) #or PREBUILT_SHARED_LIBRARY
include $(CLEAR_VARS)
LOCAL_MODULE := mylib_use_thirdlib
LOCAL_SRC_FILES := src.c
LOCAL_STATIC_LIBRARIES := thirdlib1 #or LOCAL_SHARED_LIBRARY
include $(BUILD_SHARED_LIBRARY) #如果編譯靜態庫,需要Application.mk
用cd命令移至jni目錄,運行/mnt/500G/public/NDK/android-ndk-r7b/ndk-build命令,這時命令行中可能會出現編譯錯誤,比如頭文件找不到,函數找不到等等,細心找找就能改掉。
編譯成功後,在工程目錄下libs/x86中就會生成你想要的.so庫。
9. Linux編譯一個動態庫,將所依賴的其他庫的頭文件包含了進來,但沒指定其他靜態庫的路徑和名稱
編譯能過。因為頭文件的聲明,表示在某個地方這些變數被定義了。既然被定義了,當然編譯能過。但是如果沒有那些庫,鏈接是不能過的。