關於各平台程式使用之連結庫類型。

  1. Static libraries

  2. Shared libraries

  3. Dynamically loaded libraries

參考資料來源:

  1. http://terrycslife.blogspot.tw/2010/07/so.html

  2. https://kaineshu.wordpress.com/2007/05/02/%E8%BD%89%E8%B2%BC%E7%94%A8gcc-%E8%87%AA%E8%A3%BD-library/

  3. http://www.jianshu.com/p/09994c9d8489

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"。

  1. soname是資料庫的名稱,通常以lib開頭,包含附檔名和大版號,如libexample.so.1

  2. real name是真正使用程式的資料庫名稱,包含小版號,如libexample.so.1.0.0

  3. 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.oslvs_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