2015-04-02 115 views
1

我有一個libA.so,這取決於libB.so,它位於../libB/(來自libA.c)。我試圖以這樣的方式編譯東西,我不必設置任何環境變量。我有:如何設置.so庫將搜索其他.so庫的路徑?

cc -std=c99 -c -fPIC -I../libB/ -Wall libA.c 
    cc -std=c99 -shared libA.o -L../libB -lB -o libA.so 

這個編譯得很好。當我運行加載力霸使用dlopen我得到一個程序:

dyld: Library not loaded: libB.so 
    Referenced from: libA/libA.so 
    Reason: image not found 
Trace/BPT trap: 5 

所以力霸不會在運行時發現libB。我發現這個解決方案來改變Mac OS X上運行時路徑:

install_name_tool -change libB.so @loader_path /../ libB.so libA.so

,但我想找到一個解決方案,可以在OS X和Linux上運行。再一次,我試圖讓最終用戶儘可能少做,所以我不希望他們必須設置環境變量,我必須使用cc(對我來說,這是我的Apple LLVM版本4.2(鏗-425.0 .27)(基於LLVM 3.2svn),我也希望它能在Linux上工作,所以推測cc = gcc那裏)。

編輯我的問題可能比我意識到的要複雜。我在C中創建這個動態庫,但試圖從python中使用它。我可以在python中使用libB.so(它沒有依賴關係)沒有問題,當我從python中加載libA.so時,它發現它(見上面的錯誤),只是在那個時候,libA.so意識到它沒有問題,不知道在哪裏可以找到libB.so.如果我在下面正確理解你的答案,解決方案取決於在編譯可執行文件時設置鏈接器路徑,在我的情況下這是在Python中。

當我編譯它時,沒有辦法告訴libA.so在哪裏查找libB.so嗎?我之後可以在OSX上使用install_name_tool來完成它,但是編譯器沒有辦法在OSX和Linux上工作嗎?

回答

5

底線是您的最終可執行文件必須知道您的庫駐留在哪裏。您可以通過以下兩種方式完成:(1)導出LD_LIBRARY_PATH,其中包含您的庫的路徑,或者(2)使用rpath,因此您的可執行文件知道在哪裏可以找到您的庫。導出LD_LIBRARY_PATH通常看起來是這樣的:

LD_LIBRARY_PATH=/path/to/your/lib:${LD_LIBRARY_PATH} 
export LD_LIBRARY_PATH 

我更喜歡使用rpath。要使用rpath(下面的例子爲我的擴展測試的函數庫libetf.so)編譯你的庫正常

gcc -fPIC -Wall -W -Werror -Wno-unused -c -o lib_etf.o lib_etf.c 
gcc -o libetf.so.1.0 lib_etf.o -shared -Wl,-soname,libetf.so.1 

然後編譯可執行利用這個庫,你編譯爲對象,然後給出rpath鏈接對象一個鏈接器選項。您將爲您的案例提供libA.solibB.so的路徑。建立我的testso可執行:

gcc -O2 -Wall -W -Wno-unused -c -o testetf.o testetf.c 
gcc -o testso testetf.o -L/home/david/dev/src-c/lib/etf -Wl,-rpath=/home/david/dev/src-c/lib/etf -letf 

使用ldd,以確認該可執行文件已經正確定位您的圖書館:

$ ldd testso 
     linux-vdso.so.1 (0x00007fffd79fe000) 
     libetf.so.1 => /home/david/dev/src-c/lib/etf/libetf.so.1 (0x00007f4d1ef23000) 
     libc.so.6 => /lib64/libc.so.6 (0x00007f4d1eb75000) 
     /lib64/ld-linux-x86-64.so.2 (0x00007f4d1f126000) 

注:libetf.so.1/home/david/dev/src-c/lib/etf/libetf.so.1

1

使用-rpath鏈接器選項。

-rpath dir

Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects. All -rpath arguments are concatenated and passed to the runtime linker, which uses them to locate shared objects at runtime. The -rpath option is also used when locating shared objects which are needed by shared objects explicitly included in the link; see the description of the -rpath-link option. If -rpath is not used when linking an ELF executable, the contents of the environment variable LD_RUN_PATH will be used if it is defined. The -rpath option may also be used on SunOS. By default, on SunOS, the linker will form a runtime search patch out of all the -L options it is given. If a -rpath option is used, the runtime search path will be formed exclusively using the -rpath options, ignoring the -L options. This can be useful when using gcc, which adds many -L options which may be on NFS mounted filesystems. For compatibility with other ELF linkers, if the -R option is followed by a directory name, rather than a file name, it is treated as the -rpath option.

+0

感謝您的幫助。當我man cc時,我沒有看到rpath的任何選項。不幸的是我不得不使用cc。有任何想法嗎? – Dan 2015-04-03 19:40:04

+0

當你說「cc」時,你需要更具體。 「cc」取決於系統。在Linux上它通常只是一個「gcc」的鏈接。無論如何,「rpath」是一個鏈接器選項,不是編譯器選項。因此請閱讀:man ld – kaylum 2015-04-03 20:05:46

+0

如果不清楚。使用gcc(也可能是cc)選項可以通過-Wl選項傳遞給鏈接器。 – kaylum 2015-04-03 20:29:43

3

儘管你自己沒有構建可執行文件,但是除了將libpath.so中的rpath設置爲可執行二進制文件外,其他方法幾乎相同。設置rpath時,請使用特殊的$ ORIGIN字符串,以便libB.so的位置始終與libA.so相關。

ld: Using -rpath,$ORIGIN inside a shared library (recursive)

例如:

cc -std=c99 -c -fPIC -I../libB/ -Wall libA.c 
cc -std=c99 -shared libA.o -L../libB -lB -o libA.so -Wl,-rpath,\$ORIGIN/../libB 

注意$ ORIGIN不是一個環境變量,它是由運行時加載器傳遞給鏈接時如上圖所示所以逃過直接解釋。

順便說一句,如果你喜歡跟隨類似的方法來你正在做的OS X的,你可以更改.so文件將rpath它已經使用chrpath命令編譯後 - 見:

Can I change 'rpath' in an already compiled binary?

[編輯添加]

好吧,這很有趣!在閱讀關於-rpathinstall_name的各種帖子和玩各種選項之間,我想我已經找到了適合的組合。主要伎倆似乎與力霸一個@loader_path一起被設置在libB.so的install_name的:

cc -shared -o libA.so libA.o -L../libB -lB -Wl,-rpath,@loader_path 
cc -shared -o libB.so libB.o -install_name @loader_path/../libB/libB.so 

現在libB.so總是位於相對於地方libA.so是../libB/。

+0

非常感謝您的幫助。我嘗試了你的建議,但不幸的是它不起作用 - 從第一個鏈接開始,似乎讓它工作的方式是添加-rpath-link選項,但是我的OS X編譯器不支持它。第二個鏈接中的chrpath也很棒,但是當我檢查我的Linux工作站(紅帽)時,它沒有安裝。我希望找到一個解決方案,使最終用戶不必安裝任何依賴項。任何其他想法? – Dan 2015-04-07 00:48:01

+0

看起來OS X上不支持$ ORIGIN特殊字符串...因此,在OS X上構建時應該堅持自己的計劃。在Linux上構建時使用上述技巧,或使用以下命令安裝「chrpath」:'sudo yum install chrpath'。基本上,如果你在每個平臺上以相應的方式構建它,那麼最終用戶不需要做任何事情,只需下載並運行即可。 – bgstech 2015-04-07 01:03:33

+0

謝謝,您的上述解決方案在OS X上適用於我,但當然不適用於Linux。我認爲在兩種操作系統上都必須有一種簡單的方法來做到這一點,但也許答案是沒有? – Dan 2015-04-07 11:21:42