2016-05-31 16 views
4

我在OS X上安裝了包含Homebrew的Gtk + 3包。動態庫的加載順序是否重要?

brew install gtk+3 

我可以使用​​模塊在Python中加載安裝的庫。

$ python2.6 
Python 2.6.9 (unknown, Oct 23 2015, 19:19:20) 
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> from ctypes import cdll 
>>> cdll.LoadLibrary('/usr/local/lib/libatk-1.0.0.dylib') 
<CDLL '/usr/local/lib/libatk-1.0.0.dylib', handle 7fbd10f1a250 at 10aa> 
>>> cdll.LoadLibrary('/usr/local/lib/libglib-2.0.0.dylib') 
<CDLL '/usr/local/lib/libglib-2.0.0.dylib', handle 7fbd10f0ffb0 at 10aa22dd0> 
>>> ^D 

到目前爲止好。有一件事困擾着我,如果我試圖加載 上面的兩個相同的庫,但以不同的順序,它會拋出一個符號找不到異常。

$ python2.6 
Python 2.6.9 (unknown, Oct 23 2015, 19:19:20) 
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> from ctypes import cdll 
>>> cdll.LoadLibrary('/usr/local/lib/libglib-2.0.0.dylib') 
<CDLL '/usr/local/lib/libglib-2.0.0.dylib', handle 7fad13d00d60 at 10a688210> 
>>> cdll.LoadLibrary('/usr/local/lib/libatk-1.0.0.dylib') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/ctypes/__init__.py", line 423, in LoadLibrary 
    return self._dlltype(name) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/ctypes/__init__.py", line 345, in __init__ 
    self._handle = _dlopen(self._name, mode) 
OSError: dlopen(/usr/local/lib/libatk-1.0.0.dylib, 6): Symbol not found: _g_free 
    Referenced from: /usr/local/lib/libatk-1.0.0.dylib 
    Expected in: flat namespace 
in /usr/local/lib/libatk-1.0.0.dylib 
>>> ^D 

所以,裝載atk,然後再glib,工作。另一種方式不是。誰能解釋這種行爲?

+1

是的,C庫是依賴於順序的,依賴項在順序中比依賴項晚。在C語言中(比如說)libs A B和C,如果某個用在A中的符號在C中被找到,那麼它會被B中的某個相似名稱的interloper所掩蓋。並將它們排序爲B C A中斷。在這裏,你有後一種情況,其中libatk是A,符號是_g_free,而glib *肯定*需要在_g_free的定義後加載。鏈接器跟蹤A使用_g_free需要後來的庫滿足。 –

回答

1

下面是在C命令行級顯示的同樣的問題。在這裏,我做了一個main.c,調用foo.so中的foo(),它調用bar.so中的bar(),它調用爲了好玩)glib中的g_free和g_malloc。

$ ls -Flas main.o libfoo.so libbar.so | cut -c3-13,34-37,51- 
-rwxrwxr-x 2976 libbar.so* # has bar(), which calls g_free/g_malloc 
-rwxrwxr-x 3504 libfoo.so* # has foo(), which calls bar() 
-rw-rw-r-- 2864 main.o  # has main(), which calls foo() 

正確的鏈接命令:

$ gcc -o main main.o -L. -lfoo -lbar -lglib-2.0 
$ LD_LIBRARY_PATH=. ./main 
worked! 

試圖翻轉庫加載順序:

$ gcc -o main main.o -L. -lbar -lfoo -lglib-2.0 
./libfoo.so: undefined reference to `bar' 
collect2: error: ld returned 1 exit status 

這是由於基本上你看到了同樣的問題。從「人LD」的有關條文是這樣的:

如果存檔定義這是在一些對象 其在命令行中歸檔之前出現不確定的一個符號,鏈接器將 包括相應的文件(S )從檔案中。但是,稍後在命令行中出現的對象中的未定義符號 將不會導致鏈接器再次搜索存檔。

所以當加載動態庫時,即使通過cdll,似乎也需要記住這一點。