Linux動態庫的編譯與使用 轉載
http://hi..com/linuxlife/blog/item/0d3e302ae2384d3a5343c1b1.html
Linux下的動態庫以.so為後綴,我也是初次在Linux下使用動態庫,寫一點入門步驟,以便以後能方便使用。
第一步:編寫Linux程序庫
文件1.動態庫介面文件
//動態庫介面文件getmaxlen.h
#ifndef _GETMAXLEN_H_
#define _GETMAXLEN_H_
int getMaxLen(int *sel,int N);
#endif
文件2.動態庫程序實現文件
//動態庫程序實現文件getmaxlen.c
#include "getmaxlen.h"
int getMaxLen(int *sel,int N)
{
int n1=1,n2=1;
for(int i=1;i<N;i++)
{
if(sel[i]>sel[i-1])
{
n2 ++;
if(n2 > n1)
{
n1 = n2;
}
}
else
{
n2 = 1;
}
}
return n1;
}
第二步:編譯生成動態庫
gcc getmaxlen.c –fPIC –shared –o libtest.so
由以上命令生成動態庫libtest.so,為了不需要動態載入動態庫,在命令時需以lib開頭以.so為後綴。
–fPIC:表示編譯為位置獨立的代碼,不用此選項的話編譯後的代碼是位置相關的所以動態載入時是通過代碼拷貝的方式來滿足不同進程的需要,而不能達到真正代碼段共享的目的。
–shared:指明編譯成動態庫。
第三步:使用動態庫
1. 編譯時使用動態庫
文件1.動態庫使用文件test.c
//使用動態庫libtest.so,該文件名為test.c
#include "getmaxlen.h"
int main()
{
int Sel[] = {2,3,6,5,3,2,1,2,3,4,5,6,7,6,5};
int m;
m = getMaxLen(Sel,15);
printf("%d",m);
return 0;
}
編譯命令:
gcc test.c –L . –l test –o test
–L:指明動態庫所在的目錄
-l:指明動態庫的名稱,該名稱是處在頭lib和後綴.so中的名稱,如上動態庫libtest.so的l參數為-l test。
測試:
ldd test
ldd 測試可執行文件所使用的動態庫
2. 動態載入方式使用動態庫
文件內容:
//動態庫的動態載入使用
int main()
{
void *handle = NULL;
int (*getMaxLen)(int *sel,int N);
int sel[] = {1,2,5,4,5,8,6,5,9,5,4,5,4,1};
handle = dlopen("./libtest.so",RTLD_LAZY);
if(handle == NULL)
{
printf("dll loading error.\n");
return 0;
}
getMaxLen = (int(*)(int *,int))dlsym(handle,"getMaxLen");
if(dlerror()!=NULL)
{
printf("fun load error.\n");
return 0;
}
printf("%d\n",getMaxLen(sel,15));
}
編譯命令:
gcc –ldl test1.c –o test
gcc -o test test.c ./libmytools.so
2. 如何編譯動態庫/靜態庫之編譯Qt4.8.5靜態庫
1. 下載Qt 。需要注冊一下賬號!
a) 選擇你需要的版本
3. 如何用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
在這里要廢話幾句,其實一切的二進制信息都有其運作的機制,只要弄清楚了它的機制,並能夠實現之,則任何此時此刻無法想像之事都將成為現實。當然,這兩者之間的巨大鴻溝需要頂級的設計思想和頂級的代碼來跨越。
4. Qt下如何編譯庫
akefile文件。一般是qt里自帶的qmake工具。
首先先寫好cpp和頭文件,在當前目錄下依次執行qmake -project,qmake,make即可編譯。
另外,團IDC網上有許多產品團購,便宜有口碑
5. 怎麼重新編譯android 下面的動態庫
使用動態庫來編譯動態庫
A項目的android.mk文件如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := testa
LOCAL_SRC_FILES := testa.c
include $(BUILD_SHARED_LIBRARY)
生成的libtesta.so加入到E:\workspace\android-ndk-r8e\platforms\android-8\arch-arm\usr\lib\下面
項目B的文件目錄結構如下:
jni
jni/jni/
jni/prebuilt/
jni目錄下的mk文件如下:
include $(all-subdir-makefiles)
jni/prebuilt目錄下的mk文件如下:
LOCAL_PATH := $(call my-dir)
#include $(CLEAR_VARS)
LOCAL_MODULE := libtesta
LOCAL_SRC_FILES := libtesta.so
include $(PREBUILT_SHARED_LIBRARY)
同時把libtesta.so也放入該目錄下.
jni/jni目錄下的mk文件內容:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -ltesta
LOCAL_MODULE := testb
LOCAL_SRC_FILES := testb.c
include $(BUILD_SHARED_LIBRARY)
這樣生成libtestb.so文件, 同時eclipse在打包時會把libtesta.so, libtestb.so都加入到apk文件中,如果沒有prebuilt那一步,那麼在打包時會漏掉libtesta.so, 但編譯會通過,因為編譯讀取的是編譯系統的庫文件目錄(LOCAL_LDLIBS := -ltesta), 這點需要注意
java代碼:
System.loadLibrary("testa");
System.loadLibrary("testb");
注意先後關系
6. 動態庫鏈接編譯
這里的動態的意思應該是模塊代碼是動態載入的
而不是隨著應用程序一起編譯
只要動態庫里的函數介面不變
應用程序就無需重新編譯
只需將動態庫重新編譯後替換掉舊的動態庫即可
如果動態庫的函數介面有變動
那麼應用程序就要重新編譯發布
這也是我的個人理解~~~