Linux 依賴動態庫 / 靜態庫的動態態庫 / 靜態庫

xuhc91發表於2017-05-02

一、 依賴動態庫的動態庫

libfun.so依賴動態庫libtest.so(libfun.so動態庫裡的函式intnothing()呼叫了libtest.so裡的intmytest()函式),而main.exe又呼叫了libfun.so的函式int nothing()。

 

下面兩種方式都能工作:

1> 常用的方式

g++ -shared -fPIC -o libtest.so test.cpp

g++ -shared -fPIC -o libfun.so function.cpp  -L./ -I./ -ltest ---這裡ldd能看到libfun.so依賴libtest.so(用ldd時可能要先在libfun.so所在目錄執行下export LD_LIBRARY_PATH=./)

g++ -o main.exe main.cpp -L./ -I./ -lfun    ---編譯libfun.so的時候已經指定了依賴libtest.so,這裡就不需要再指定了

 

或者

 

2>不常用的方式

g++ -shared -fPIC -olibtest.so test.cpp

g++ -shared -fPIC -o libfun.so function.cpp    ---這裡ldd可知,libfun.so沒有依賴libtest.so

g++ -o main.exe main.cpp -L./ -I./ -lfun -ltest ---因為編譯libfun.so的時候沒有指定它依賴libtest.so,所以要加上-ltest

 

從2>可知,Linux下面生成動態庫的時候,即使動態庫裡有沒有定義的函式,在編譯連結的時候,預設不會提示錯誤,是能通過的。

但是,當可執行檔案在連結這個有未定義函式的動態庫的時候則會報錯。具體解釋可通過man ld檢視說明。

 

--allow-shlib-undefined

--no-allow-shlib-undefined

           Allows or disallows undefinedsymbols in shared libraries.  This switchis similar to --no-undefined except that it determines the behaviour when theundefined symbols are in a shared

           library rather than a regular objectfile.  It does not affect how undefinedsymbols in regular object files are handled.

 

           The default behaviour is to reporterrors for any undefined symbols referenced in shared libraries if the linkeris being used to create an executable, but to allow them if the linker is

           being used to create a sharedlibrary.

 

           The reasons for allowing undefinedsymbol references in shared libraries specified at link time are that:

 

           ·   A shared library specified at link time maynot be the same as the one that is available at load time, so the symbol mightactually be resolvable at load time.

 

           ·   There are some operating systems, eg BeOSand HPPA, where undefined symbols in shared libraries are normal.

 

               The BeOS kernel for examplepatches shared libraries at load time to select whichever function is mostappropriate for the current architecture. This is used, for example, to

               dynamically select anappropriate memset function.

 

 

從此特性引申一點,經過測試發現,無論是在靜態庫或是動態庫中,都可以只宣告一個函式而不定義此函式,但是在庫中可以呼叫此未定義的函式,生成庫的時候都能成功。然後在用到此靜態庫或是動態庫的可執行程式裡定義此函式,編譯連結好此可執行程式後執行,發現執行時庫中呼叫的此函式的實現正是可執行程式中定義的函式體。此特性即為回撥函式。

原來一直以為只有靜態庫才能這樣用,因為靜態庫生成的時候是不需要連結的。現在才知道,動態庫靜態也能這樣用。


二、依賴動態庫 / 靜態庫的動態態庫 / 靜態庫

靜態庫只是一堆object物件的集合,使用ar命令可以將編譯產生的.o檔案打包成.a靜態庫。

生成靜態庫只有編譯,而沒有連結;而動態庫在生成的時候時既有編譯的動作也有連結的動作。

靜態庫在被別的程式(可執行程式或是動態庫)連結的時候,連結器會將程式中使用到函式的程式碼從靜態庫檔案中拷貝到應用程式中的。

靜態庫生成時是沒有連結的,所以生成它的時候不需要指定它所依賴的外部庫;動態庫生成時是有連結動作的,那當然就要指定它依賴哪些外部庫了。

如:

$ gcc -c libhello -o libhello.o
$ ar rcs libhello.a libhello.o

這裡先編譯得到.o檔案,然後再用ar命令打包即得到了靜態庫,它是沒有連結動作的。

如一中所述,如果一個動態庫依賴一個動態庫,則該動態庫是會知道它所依賴的動態庫的。那麼,如果一個動態庫依賴一個靜態庫呢?這時,在生成這個動態庫時,它就會將靜態庫的程式碼拷貝到動態庫程式中的。例如, liba.so 依賴 libb.a, 則在生成liba.so時必須要在makefile中指定依賴靜態庫libb.a,且要指定libb.a為查詢目錄。同時如果可執行程式c.out依賴liba.so,則a.out只需要指出它依賴動態庫liba.so就可以了,a.out不需要再去連結靜態庫libb.a了。

還有,一個靜態庫依賴一個靜態庫 / 動態庫呢? 因為如上所述,生成靜態庫的時候它是沒有連結動作的,所以不需要指定它所依賴的外部靜態庫或是動態庫。那麼你也許要問了,沒有指定依賴,那靜態庫引用的外部庫中的函式怎麼辦呢? 這個就要看看我轉的另外一篇博文了 連結器如何使用靜態庫來解析引用。在程式連結靜態庫的時候,它會去掃描該靜態庫中哪些未解析符號,然後會在其它的指定靜態庫或目標檔案(動態庫或是main函式所對應.o檔案)中去掃描看是否有此未解析的符號,如果有,則連結到此對應的定義。所以,只要在連結靜態庫的地方再去指定連結該靜態庫的依賴庫就可以了。

相關文章