linux下動態共享庫的建立,使用與更新(包括ldconfig的使用)
【原文:http://blog.csdn.net/the9thbit/article/details/5902107】
一 建立並編譯共享庫
動態連結庫一般以lib開頭,形如libmymodule.so.1.0.0.
後面跟的三個版本號,從左到右的含義為:
(1) 大版本號,當介面變得和之前不相容,則新增一個大版本號。
(2) 一般增加了介面,不過舊的介面不變,則新增此版本號。
(3) 介面不做任何變化,只是實現做了修改,則新增此版本號。
假設我們的庫只包含 module.cpp, 則用命令
- g++ -fPIC -Wall -c module.cpp
生成module.o,再用命令
- g++ -shared -Wl,-soname,libmymodule.so.1 -o libmymodule.so.1.0.0 module.o
生成libmymodule.so.1.0.0共享庫。這裡的libmymodule.so.1.0.0也叫做共享庫的real name.
- -fPIC是使生成的目標檔案“位置無關(Position Independent Code)”從而可以被多個程式共享。
- -shared 指定產生共享庫。
- -Wl,-soname,libmymodule.so.1 指定共享庫的soname為libmymodule.so.1,若不指定,則無soname. soname的作用後面會提到。可以用objdump -p libmymodule.so.1.0.0 | grep SONAME 檢視soname.
一般soname帶且只帶大版本號,比如這裡的libmymodule.so.1, 是因為共享庫的相互相容的不同版本,都具有相同的soname(在升級的時候,需要用soname來對應)。而如果大版本號變了,意味著介面變得不相容了,也就沒有必要讓這個版本和之前的共享庫相容了。這個時候,啟用一個新的soname是更好的做法。
二 編譯主程式
因為gcc中,用-l引數指定的庫檔案必須滿足格式lib*.so 所以我們需要建立軟連線libmymodule.so, 並令其指向libmymodule.so.1.0.0
- ln -s libmymodule.so.1.0.0 libmymodule.so
這裡的libmymodule.so就是所謂的"link name"。
假設我們的主程式(相對於庫來說),程式碼在main.cpp裡,則用命令
- g++ -o main main.cpp -L. -lmymodule
生產可執行程式main。注意link name只在編譯的時候需要,主程式會記住根據這個檔案最終所指的共享庫的soname,用來在執行的時候,查詢載入動態庫。如果共享庫沒有指定soname, 那麼主程式會記住這個'link name",也就是lib*.so這樣形式的名字,做為soname, 在執行的時候,用這個名字來查詢載入動態庫。
- -L指定搜尋庫的資料夾,
- -l 指定所依賴的庫。注意這裡需要去掉前面的“lib”和後面的“.so”
三 執行期
這個時候,執行./main會出現以下錯誤:
./main: error while loading shared libraries: libmymodule.so.1: cannot open shared object file: No such file or directory
使用ldd main可以檢視所依賴的動態庫是否被滿足,執行“ldd main":
發現有一行libmymodule.so.1 => not found,說明在執行期,載入器沒有找到對應的共享庫檔案。
載入器會在以下地方查詢main程式中記住的所需要的庫的soname:
(1) /etc/ld.so.cache 這是一個cache,存放soname到共享庫檔案的soname link (一個檔名為soname的軟連線) 的對映(key->value值對)。
(2) /usr/lib 和 /lib
(3) 環境變數LD_LIBRARY_PATH指定的資料夾。
可以用ldconfig 命令,解決這個問題。ldconfig主要做2件事情:
一是掃描/lib和/usr/lib和/etc/ld.so.conf裡指定資料夾,對裡面的共享庫建立soname link (ldconfig會根據檔名裡的版本號,自動找到最新的共享庫檔案,並把soname link指向這個最新的共享庫檔案)
二是更新/etc/ld.so.cache,建立soname到soname link的對映。
載入器如果在ld.so.cache中查到所需的soname,則會依次找到 soname-->soname link-->實際的共享庫檔案。如果找不到,則會在/usr/lib和/lib中查詢檔名為soname的檔案,作為共享庫檔案載入。注意,在這裡,載入器不會去找/etc/ld.so.conf裡指定的資料夾,只會找/usr/lib和/lib。所以如果在/etc/ld.so.conf裡指定的資料夾,增加了soname link,必須要執行ldconfig來更新ld.so.cache。
ldconfig -n /path/to/dir 命令可以指定某資料夾,不過只會做第一件事,也就是建立soname link-->實際的共享庫檔案。不會更新ld.so.cache 所以不需要root許可權。
ldconfig -p 命令可以列印ld.so.conf裡已經有的鍵值對。
好了,瞭解了以上知識,我們可以用以下方法解決找不到共享庫的問題:
(a) 將libmymodule.so.1.0.0拷到/lib或者/usr/lib裡,或者/etc/ld.so.conf指定的資料夾,然後執行sudo ldconfig. 於是ldconfig會自動在/lib或/usr/lib或/etc/ld.so.conf指定的資料夾裡生成soname link (檔名為libmymodule.so.1) 指向libmymodule.so.1.0.0,然後在ld.so.cache中增加libmymodule.so.1到/lib /libmymodule.so.1或/usr/lib/libmymodule.so.1的對映(前者是個名字,後者是個軟連線檔案)
(b) 使用LD_LIBRARY_PATH=/PATH/TO/SO ./main來執行程式。前提是在/PATH/TO/SO中建立一個名字為soname的軟連線,使其指向實際的共享檔案。
(c) 在/lib或/usr/lib中,手動建立軟連線 libmymodule.so.1 令其指向實際的共享庫檔案 libmymodule.so.1.0.0。 因為前面提到的,載入器在ld.so.cache中找不到要找的鍵為soname的項,會在/lib或/usr/lib中找名字為soname的檔案。這方法雖然可以用,不過感覺比較粗暴。不推薦。
四 升級共享庫
如果是用上述(a)方法使用共享庫的,只需要將新的共享庫,比如 libmymodule.so.1.0.1拷到原來的目錄(/lib或/usr/lib或者/etc/ld.so.conf指定的資料夾),然後執行 ldconfig即可。ldconfig會更新soname link, 使其指向最新的共享庫檔案libmymodule.so.1.0.1,ld.so.cache不需要更新。
如果是用上述(b)(c)方法是用共享庫的,需要更新相應的軟連線,使其指向最新的共享庫檔案。
五 動態載入共享庫
在主程式中動態載入共享庫時,如果指定的是絕對路徑("/"開頭的),則載入該絕對路徑指向的共享庫檔案。如果不是絕對路徑,而是一個檔名,則將這個檔名當作soname,然後依照上述的方法,查詢載入相應的共享庫檔案。
六 注意點
如果在共享庫中,要用到主程式的變數或者方法,要在編譯主程式時,加上-rdynamic引數,使得所有名字在共享庫的空間中可見。
相關文章
- linux下的靜態庫與動態庫Linux
- 動態連結庫(DLL)的建立和使用
- Linux共享庫、靜態庫、動態庫詳解Linux
- C靜態庫的建立與使用--為什麼要引入靜態庫?
- linux下使用boost.python呼叫c++動態庫LinuxPythonC++
- cocoaPods私有庫的建立與使用
- iOS動態庫的使用iOS
- 簡述Linux下的靜態庫和動態庫Linux
- 動態庫使用
- 動態庫的生成和使用(二)
- Linux下共享VG改變活動狀態Linux
- 動態庫的建立和呼叫
- CE的使用及靜態地址與動態地址
- Linux下建立root/普通使用者Linux
- 在 Linux中如何使用動態連結模組庫?Linux
- 動態連結庫的生成和使用(二)
- 如何使用 JuiceFS 建立 WebDAV 共享UIWeb
- 靜態庫和動態庫的製作以及Bundle資原始檔的使用
- linux下靜態連結庫和動態連結庫的區別有哪些Linux
- 使用 arch-ppa 建立你自己的 Arch Linux 軟體庫Linux
- android下java的靜態庫和動態庫AndroidJava
- 不停機狀態下使用Django建立索引Django索引
- oracle 序列的建立與使用Oracle
- Linux下C++ libtorrent庫使用LinuxC++
- AutoUpdater.NET自動更新庫使用
- Linux動態庫Linux
- Python中動態類和動態方法的建立與呼叫Python
- 使用dlopen載入動態庫
- 關於MNN工程框架編譯出來的靜態庫和動態庫的使用框架編譯
- 使用udev高效、動態的管理Linux裝置檔案devLinux
- linux 環境下 elasticsearch 及 python 相關庫的使用LinuxElasticsearchPython
- SqlServer遊標的建立與使用SQLServer
- iOS Tangram(VirtualView)動態元件的學習與使用iOSView元件
- Blazor元件的new使用方式與動態彈窗Blazor元件
- 靜態庫與動態庫
- [Linux]動靜態庫Linux
- Linux使用者的建立和刪除Linux
- 【Linux】Rsync的剖析與使用Linux
- 使用NAS動態儲存卷建立有狀態應用