linux下使用非標準位置的 第三方庫

原貼:http://soho-schubert.blogspot.com/2007/08/linux.html

Linux編程使用庫

昨天寫了一小段測試MySQL的C代碼,編譯順利,但運行時報告找不到庫,系統是FC4,MySQL是直接下載的Binary:
# gcc test_mysql.c -o test_mysql -L/usr/local/mysql/lib -lmysqlclient
#./test_mysql: error while loading shared libraries:
libmysqlclient.so.15: cannot open shared object file: No such file or directory

雖 然知道這一定是系統沒有找到加載libmysqlclient.so庫的路徑,並且可以把libmysqlclient.so.15 copy到/usr/lib解決,但不知道該原理和更好的方法。於是重看GUN/Linux編程指南(Kurt Wall)第10章,答案如下。

運行時使用非標準位置/usr/lib和/lib下的庫的方式有三種:
(1) 設置$LD_LIBRARY_PATH=庫所在目錄(多個目錄用:分隔),系統加載工具ld.so/ld-linux.so將順序搜索變量指定的目錄。例如#$LD_LIBRARY_PATH=/usr/local/mysql/lib ./test_mysql
(2) 以root身份把庫路徑加入/etc/ld.so.conf或在/etc/ld.so.conf.d中創建特定的.conf文件,然後運行 ldconfig更新/etc/ld.so.cache。例如:在/etc/ld.so.conf.d下創建文件mysql.conf寫入/usr /local/mysql/lib
(3) 另一種辦法就是把需要的庫copy到/usr/lib或/lib,但這不是建議的方法,特別是儘量避免copy發到/lib。但這種方法可以在編譯時免去用-L選項。

共享庫搜索順序一般是$LDLIBRARY_PATH,/etc/ld.so.cache, /usr/lib, /lib

========
另外,順便溫習了一下其它和庫相關的基礎知識:

庫的目的是代碼重用,提供共用的功能,某個程序爲別的程序提供公開的接口等。

命名和編號:
(1) 所有庫名以lib開頭,gcc在-l指定的文件名前自動插入lib,如libmysqlclient就用-lmysqlclient
(2) .a是靜態庫(archive),如 libmysqlclient.a
(3) .so是共享庫(shared object),如libmysqlclient.so
(4) 編號格式:library_name.major_num.minor_num.patch_num,如libmysqlclient.so.15.0.0
(5) _g和_p: /usr/lib/libform_g.a 中的_g表示這是libform.a的調試庫,用locate _g.a會發現很多類似的庫,但我用locate _g.so沒有發現FC4有此類庫;libxxx_p.a中的_p表示這是libxxx.a的性能分析庫(profiling),但我用locate _p.a和locate _p.so沒有發現FC4有此類路庫。

庫要和接口頭文件配合使用,常見的庫如:
libc.so (不需頭文件) 標準C庫
libdl.so (dlfcn.h) 讓程序在運行是加載和使用庫代碼,而不在編譯時鏈接庫
libglib.so (glib.h) Glib工具函數,例如hash, string等
libgthread.so (glib.h) 對Glib的線程支持
libm.so (math.h) 標準C數學庫
libpthread.so (pthread.h) POSIX標準Linux線程庫
libz.so (zlib.h) 通用壓縮程序庫

庫操作命令:
(1) nm 列出目標文件或二進制文件的所有符號
(2) ar 創建靜態庫和符號索引
(3) ldd 列出程序正常運行所需要的共享庫,例如
# ldd test_mysql
linux-gate.so.1 => (0x00c59000)
libmysqlclient.so.15 => /lib/libmysqlclient.so.15 (0x009a1000)
libc.so.6 => /lib/libc.so.6 (0x0038b000)
libpthread.so.0 => /lib/libpthread.so.0 (0x004f8000)
libcrypt.so.1 => /lib/libcrypt.so.1 (0x002f0000)
libnsl.so.1 => /lib/libnsl.so.1 (0x00320000)
libm.so.6 => /lib/libm.so.6 (0x004bd000)
/lib/ld-linux.so.2 (0x0036d000)
(4) ldconfig 和動態鏈接和裝載工具ld.so/ld-linux.so一起決定位於/usr/lib和/lib下的so庫所需的鏈接。ldconfig創建一個從實際 庫到so庫名的符號鏈接。注意/etc/ld.so.cache, /etc/ld.so.conf ldconfig -p列出/etc/ld.so.cache內的庫對照鏈接。

環境變量:
動態鏈接器ld.so/ld-linux.so使用一些環境變量:
$LDLIBRARY_PATH : 格式類似$PATH,:分隔,非標準位置/usr/lib和/lib下的庫或者/etc/ld.so.cache中沒有的庫,需要加入該變量才能被搜索到。
$LD_PRELOAD: 空格分隔,定義需要在最前面加載的庫。也可以由/etc/ld.so.preload文件代替

靜態庫和共享庫都是包含object文件的文件。

建立和使用靜態庫:
(1) 把代碼編譯成目標文件,如gcc -c libxxx.c -o libxxx.o
(2) ar: ar -rcs linxxx.a linxxx.o
(3) gcc -static: gcc test.c -o test -static -L. -lxxx
(4) 用file檢查靜態鏈接的可執行文件
(5) 用nm檢查符號,靜態鏈接沒有未定義符號

共享庫佔用系統資源少(磁盤和內存),運行時根據共享鏈接從單個文件加載,速度快,維護方便。在運行時,ld.so/ld-linux.so把二進制文件中的符號名鏈接到適當的so庫上。

建立和使用共享庫:
(1) gcc -fPIC 產生與位置無關的代碼,如gcc -fPIC -g -c libxxx.c -o libxxx.o
(2) gcc -shared和-soname,如gcc -g -shared -Wl,–soname, -libxxx.so -o libxxx.so.1.0.0 libxxx.o (注意-Wl,–soname, -libxxx.so 中間沒有空格)
(3) gcc -Wl 把參數傳遞給鏈接器ld
(4) gcc -l顯式鏈接C庫

編譯時指定非標準位置/usr/lib和/lib下的庫的方式是用-L庫目錄指定。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章