關於各平台程式使用之連結庫類型。
-
Static libraries
-
Shared libraries
-
Dynamically loaded libraries
參考資料來源:
-
https://kaineshu.wordpress.com/2007/05/02/%E8%BD%89%E8%B2%BC%E7%94%A8gcc-%E8%87%AA%E8%A3%BD-library/
Object File :
通常副檔名為.o
或是.obj
,後者為Windows使用的格式。
將.c
或.cpp
、.cxx
的C語言程式碼包裝成的物件檔,無法直接使用。
使用編譯工具的"Link"功能可以將這些單獨的物件檔合併成連結庫或是可執行檔。
Static libraries - 靜態資料庫 :
通常副檔名為.a
。
作用方式:將連結庫包入程式中執行,處理效率高,缺點是檔案大且不易更新。
若要建立一個靜態資料庫,可以使用DllTool從.dll
檔解出或是用GNU的ar
工具連結物件檔編譯。
ar
的指令中,rcs
或是-r
後接上輸出的檔案名稱,如下:
ar rcs libmylib.a first.o second.o
產生靜態資料庫後,可以使用gcc的-L
和-l
指令連結,對象包含程式碼、物件檔和其他靜態資料庫。
Shared libraries - 共用資料庫 :
通常副檔名為.so
,後面可加掛版本編號。
作用方式:資料庫和執行檔是分離的,剛開始就要載入,並且資料庫必須一直和執行檔待在一起,優點是修改方便。
gcc在產生物件檔時必須加上-fPIC
參數,紀錄"position-independent code",就是獨立位置碼,以紀錄存取位置的資訊。沒有使用的話只會用相對位置,不利於共享內容。
再來將物件檔合併成資料庫時,加上-shared
參數,接著要自訂義"soname"、"real name"、"linker name"。
-
soname是資料庫的名稱,通常以
lib
開頭,包含附檔名和大版號,如libexample.so.1
。 -
real name是真正使用程式的資料庫名稱,包含小版號,如
libexample.so.1.0.0
。 -
linker name是連結時的資料庫名稱,不包含版號,如
libexample.so
。
gcc使用-Wl
參數向內建的Link工具"ln"傳入資訊,如下:
gcc -shared -Wl,-soname,libexample.so.1 -o libexample.so.1.0.0 first.o second.o
使用-Wl,-soname
定義soname;輸出的檔案名稱為real name;使用-l
或-l:
連結的名稱為linker name。
尋找了下維基百科,似乎也能使用-h
和-soname=
來定義soname的名稱。
資料庫連結時使用ln
指令連結兩個.so
檔。使用-s
參數為軟連結,類似捷徑式的參照;使用-d
參數為硬連結,類似副本的備份。
最後必須用以下指令為real name創造linker name和soname的檔案(使用-s
或-d
就隨喜好了)。
linker name
ln -s libexample.so.1.0.0 libexample.so
soname
ln -s libexample.so.1.0.0 libexample.so.1
之後可以用GNU的另一個工具"objdump"檢查連結。
objdump -p libexample.so.1.3 | grep SONAME
產生共用資料庫後,可以像靜態資料庫一樣包裝,也可以用程式呼叫。
連結時有同名資料庫時會以共用資料庫優先,加上-static
參數可以指定靜態資料庫。
而調用資料庫時是先找soname的檔案,否則會尋找linker name的檔案,可執行檔亦同。
Dynamically loaded libraries - 動態載入庫 :
為Windows中.dll
檔標準的模式,不過並非所有.dll
都是如此。
作用方式:使用時才會載入,編譯時不須要相關資料庫檔案,因此常用於附加元件。
使用一套DLL function來處理,標頭檔和編譯的程式碼中都會使用來傳遞訊息。
gcc編譯時要加上-ldl
參數連結。
後來發現gcc有時編譯「成功」的樣子可能包含著錯誤。
今天測試了一些方法,但是明明CDemo和Python的.so
都是差不多的參數,編譯出的結果卻不如預期。
libslvs.so
g++ -shared -o libslvs.so ../obj/util.obj ... ../obj/w32util.obj
_slvs.so
g++ -shared -o _slvs.so ../obj/util.obj ... ../obj/slvs_wrap.o -LW:/Anaconda3/libs -lPython35 -L. -l:libslvs.so
如果編譯_slvs.so
時不加上後面的-LW:/Anaconda3/libs
、-lPython35
等等就會因為slvs_wrap.o
的slvs_wrap.cxx
出問題,但是沒加上就和libslvs.so
一樣了。
但是這樣另一個問題就產生了,因為編出來的_slvs.so
是「可執行檔」,不指定-o _slvs.so
的話就會編譯成a.exe
,所以其他Python程式碼都找不到(有搬到虛擬機的Ubuntu測試,也找不到)。
想過學範例用.c
跳過Object File的階段直接轉成.so
檔,但是只有libslvs.so
成功,_slvs.so
反而在系統暫存檔Temp資料夾中找不到Python連結。
之後稍微看了一下SWIG轉出的slvs.py
結構,呼叫的.py
檔必須先導入slvs.py
後,slvs.py
會視Python版本取用_slvs.so
的內容,再傳給需要的.py
檔,所以slvs.py
和_slvs.so
都必須和撰寫的.py
檔放在一起。
Comments
comments powered by Disqus