日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

linux 编译查看链接库详情,Linux环境下的编译,链接与库的使用

發(fā)布時(shí)間:2023/12/20 linux 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 编译查看链接库详情,Linux环境下的编译,链接与库的使用 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

鏈接參數(shù)控制

鏈接器中提供了-dn -dy 參數(shù)來(lái)控制使用的是動(dòng)態(tài)庫(kù)還是靜態(tài)庫(kù),-dn表示后面使用的是靜態(tài)庫(kù),-dy表示使用的是動(dòng)態(tài)庫(kù)

例:

g++ -Lpath -Wl,-dn -lx -Wl,-dy -lpthread 這樣如果在path路徑下有l(wèi)ibx.so和libx.a這個(gè)時(shí)候只會(huì)用到 libx.a.

注意在最后的地方如果沒(méi)有-Wl,-dy 讓后面的庫(kù)都使用動(dòng)態(tài)庫(kù),可能會(huì)報(bào)出 “cannot find -lgcc_s” 的錯(cuò)誤,這是由于glibc的.a庫(kù)和.so庫(kù)名字不同,–static會(huì)自動(dòng)處理,但是 -Wl,-dy卻不會(huì)去識(shí)別這個(gè)問(wèn)題.

小提示:

如果使用–static, 由于-dy的使用導(dǎo)致后面的庫(kù)都是共享庫(kù)(dy強(qiáng)制屏蔽了靜態(tài)庫(kù)),這個(gè)時(shí)候編譯出來(lái)的程序和只有動(dòng)態(tài)庫(kù)的情況下強(qiáng)制使用–static編譯一樣都會(huì)報(bào)錯(cuò)

運(yùn)行報(bào)錯(cuò) ”undefined reference to `xxx()’ ” 對(duì) 于動(dòng)態(tài)鏈接庫(kù),實(shí)際的符號(hào)定位是在運(yùn)行期進(jìn)行的.在編譯.so的時(shí)候,如果沒(méi)有把它需要的庫(kù)和他一起進(jìn)行聯(lián)編,比如libx.so 需要使用uldict, 但是忘記在編譯libx.so的時(shí)候加上-luldict的話,在編譯libx.so的時(shí)候不會(huì)報(bào)錯(cuò),因?yàn)檫@個(gè)時(shí)候libx.so被認(rèn)為是一個(gè)庫(kù),它里面 存在一些不知道具體實(shí)現(xiàn)的符號(hào)是合法的,是可以在運(yùn)行期指定或者編譯另外的二進(jìn)制程序的時(shí)候指定.

如果是采用 g++ -Lpath -lx 的方式進(jìn)行編譯,鏈接器會(huì)發(fā)現(xiàn)所需要的uldict的符號(hào)表找不到從而報(bào)錯(cuò),但是如果是程序采用dlopen的方式載入,由于是運(yùn)行期,這個(gè)程序在這個(gè)地 方就直接運(yùn)行報(bào)錯(cuò)了. 另外還有一種情況就是一個(gè)對(duì)外的接口在動(dòng)態(tài)庫(kù)中已經(jīng)聲明定義了,但是忘記實(shí)現(xiàn)了,這個(gè)時(shí)候也會(huì)產(chǎn)生類似的錯(cuò)誤.

如果在運(yùn)行期報(bào)出這樣的錯(cuò)誤,就要注意是否是由于某些庫(kù)沒(méi)有鏈接進(jìn)來(lái)或者某些接口沒(méi)有實(shí)現(xiàn)的原因產(chǎn)生

日志庫(kù)問(wèn)題 其實(shí)不只是日志庫(kù)存在這樣的問(wèn)題,其他需要同時(shí)被多個(gè)動(dòng)態(tài)庫(kù)以及主程序同時(shí)使用的函數(shù)其實(shí)都存在這樣的問(wèn)題.這里主要以日志庫(kù)的問(wèn)題為例來(lái)說(shuō)明這些問(wèn)題.

有 一個(gè)程序,它通過(guò)dlopen的方式調(diào)用了一個(gè).so文件. 在這個(gè)主程序中和.so中都使用了日志庫(kù),主程序中使用ul_openlog打開(kāi)了日志, 在.so中沒(méi)有用ul_openlog打開(kāi)日志.這個(gè)時(shí)候發(fā)現(xiàn),主程序中的日志正常輸出,但.so中的日志卻直接輸出到了標(biāo)準(zhǔn)出錯(cuò).

這個(gè)問(wèn) 題的原因在前面的其實(shí)已經(jīng)提到了,在默認(rèn)情況下主程序中使用的接口對(duì)于.so是不可見(jiàn)的,.so所在的代碼空間與主程序的代碼空間是隔離的,這個(gè)時(shí) 候.so調(diào)用的ul_writelog其實(shí)是沒(méi)有經(jīng)過(guò)ul_openlog的那塊代碼空間,由于ul_log庫(kù)使用了一些static變量(如果是帶 comlog的ul_openlog那還有全局符號(hào)),只有在ul_writelog, ul_openlog都是在同一塊空間上的時(shí)候才會(huì)起作用.

這個(gè)問(wèn)題的一個(gè)最簡(jiǎn)單的解決方案是

在主程序的鏈接的時(shí)候加入-rdynamic,仍然鏈接libullib.a庫(kù) 編譯動(dòng)態(tài)鏈接庫(kù)時(shí),不加鏈接libullib.a庫(kù) 其實(shí)動(dòng)態(tài)庫(kù)這里是否鏈了libullib.a已經(jīng)不重要了,在有-rdynamic的情況下,.so中如果有與主程序同名的函數(shù)那么會(huì)優(yōu)先調(diào)用主程序中的函數(shù), 動(dòng)態(tài)庫(kù)不鏈接libullib.a倒是可以省點(diǎn)空間

但是這種方式在某些情況還是不能完全解決問(wèn)題

假 設(shè)有A.so, B.so,主程序main, 在A.so中調(diào)用了ul_openlog, B.so中沒(méi)有調(diào)用ul_openlog, 但調(diào)用了ul_writelog. 在主程序中沒(méi)有調(diào)用ul_log中的任何接口和使用任何變量.這種情況下即時(shí)使用了-rdynamic還是會(huì)導(dǎo)致在 A.so中正常輸出日志,但在B.so中卻把日志輸出到標(biāo)準(zhǔn)出錯(cuò).

這個(gè)問(wèn)題的主要原因在于,gcc在鏈接的時(shí)候是以.o為單位的,如果一 個(gè).o中的符號(hào)沒(méi)有被外部所使用,那么在鏈接的時(shí)候就不會(huì)把這個(gè).o中的符號(hào)給鏈接進(jìn)行.so或者二進(jìn)制程序中.在上面的問(wèn)題中主程序里面沒(méi)有調(diào)用到日志 庫(kù)中的任何符號(hào),所以在鏈接的時(shí)候就不會(huì)把ullib中的ul_openglog和ul_writelog給鏈接進(jìn)行主程序中,這個(gè)時(shí)候即使有 -rdynamic也是做不到讓.so中的動(dòng)態(tài)鏈接庫(kù)都使用.

這個(gè)問(wèn)題一般有下面幾種方案:

載入A.so的時(shí)候使用RTLD_GLOBAL參數(shù),把A.so中的所有的符號(hào)都變成對(duì)外可見(jiàn),這樣A.so和B.so的ul_writelog都在一塊代碼空間中了 編譯主程序的時(shí)候鏈接ullib的地方由-lullib改為 -Wl,–whole-archive -lullib -Wl,–no-whole-archive, 同時(shí)加上-rdynamic. -Wl, –whole-archive是鏈接參數(shù),它表示把ullib的中所有的符號(hào)都鏈接進(jìn)主程序中,而不管主程序是否調(diào)用了ullib中的符 號(hào).-Wl,–no-whole-archive表示后面的鏈接取消–whole-archive的行為,畢竟其他的庫(kù)沒(méi)有必要采用這種方式全部鏈接 進(jìn)來(lái). 在主程序中隨便調(diào)一下ul_log中的符號(hào),比如可以先隨便ul_openlog一下,然后ul_closelog, 后面再進(jìn)行動(dòng)態(tài)庫(kù)調(diào)用. 把libullib.a用 ar x 命令還原成多個(gè).o文件,采用直接鏈接的方式使用ul_log.o. 上 面的幾個(gè)問(wèn)題的產(chǎn)生主要還在于靜態(tài)鏈接和動(dòng)態(tài)鏈接混用,而兩種鏈接方式又存在不一樣的地方.事實(shí)上如果我們把ullib庫(kù) 采用動(dòng)態(tài)鏈接庫(kù)的方式編譯成 libullib.so, 采用前面的方式在編譯期鏈接libullib.so,并且設(shè)置LD_LIBRARY_PATH, 上面的2個(gè)問(wèn)題都不會(huì)存在. 編譯期使用的.so,是全局可見(jiàn)的,不需要-rdynamic也可以被dlopen的動(dòng)態(tài)庫(kù)所用到,由于是動(dòng)態(tài)鏈接庫(kù),所以 包含了所有的符號(hào),不會(huì)像靜態(tài)庫(kù)那樣只包含了所用到的.o中的符號(hào). 事實(shí)上這也是多數(shù)第三方程序的解決方案

主程序中使用-rdynamic會(huì)對(duì)后續(xù)的升級(jí)造成一些麻煩:

加上-rdynamic后,像日志庫(kù)這樣的基礎(chǔ)如果需要升級(jí), 那么就必須要升級(jí)主程序, 使用的.so無(wú)論如何升級(jí)所用到的ul_writelog都是主程序中的. 主程序中除了日志庫(kù),還會(huì)有其他庫(kù)或者函數(shù)的存在, 這些函數(shù)如果不是static的就有可能與 dlopen打開(kāi)的so中的函數(shù)混到一起,造成困惑 如果.so中需要打印它自己的日志, 那樣需要comlog本身功能的支持才可以實(shí)現(xiàn),而不能簡(jiǎn)單的使用ul_writelog來(lái)實(shí)現(xiàn) 但是如果主程序中沒(méi)有使用-rdynamic,那么又有下面的這些麻煩 dlopen打開(kāi)的動(dòng)態(tài)庫(kù)日志是打印自己的, 不能和主程序統(tǒng)一在一起. 如果.so的程序和主程序open的是同一個(gè)日志,這相當(dāng)于多進(jìn)程打日志, 那必須要comlog的支持,ullog本身不支持多進(jìn)程打同一個(gè)日志. 如果主程序中用dlopen+RTLD_GLOBAL的打開(kāi)了某個(gè).so 日志的問(wèn)題就可能影響到其他的.so中的調(diào)用. 同時(shí)對(duì)于一些老程序, 升級(jí)前后-rdynamic 可能也會(huì)產(chǎn)生影響,比如兩次ul_openlog 這里對(duì)于類似日志庫(kù)這種需要全局狀態(tài)變量支持的庫(kù)提出另外方案

編譯一個(gè)專門的.so, 這個(gè).so中包括了其它.so中所需要的所有和全局量相關(guān)的接口 2. 主程序不使用-rdynamic編譯, 但打開(kāi)上面的.so的時(shí)候,采用RTLD_GLOBAL方式,并且是第一個(gè)打開(kāi) 3. 除了打開(kāi)第一個(gè) .so, 其它的.so都不使用RTLD_GLOBAL方式, 并且在編譯的時(shí)候都不把和第一.so相關(guān)的庫(kù)聯(lián)編 4. 第一個(gè).so的升級(jí)需要保證沒(méi)有其它.so在運(yùn)行才可以dlclose, 重新dlopen

這個(gè)問(wèn)題首先需要明確需求, 到底是希望每個(gè).so打自己獨(dú)立的日志,還是和主線程統(tǒng)一

這 里要注意另外一個(gè)問(wèn)題就是目前的ullib 日志庫(kù)情況比老的ullog要復(fù)雜, 在comlog中引入一些extern 出來(lái)的全局變量 在采用dlopen的時(shí)候,對(duì)于一般符號(hào),一般都是主程序和動(dòng)態(tài)庫(kù)在兩塊空間中, 但是對(duì)于使用extern出來(lái)的變量主程序和動(dòng)態(tài)庫(kù)都是在一塊空間中(注:由于32位下不用-fPIC也可以編譯so, 在沒(méi)有-fPIC的情況也是分開(kāi)的, 但是由于64位一定要-fPIC所以一定會(huì)出現(xiàn)同一塊空間的問(wèn)題), 對(duì)于這個(gè)問(wèn)題的解決方案是在動(dòng)態(tài)庫(kù)鏈接的時(shí)候加上 -Wl,-Bsymbolic 參數(shù)將動(dòng)態(tài)庫(kù)的空間和主程序的空間強(qiáng)行分開(kāi)。

上面有提到 編譯動(dòng)態(tài)鏈接庫(kù)時(shí),不加鏈接libullib.a庫(kù),但主程序使用-rdynamic, 這里主要是為了避免使用到了不同的ullib導(dǎo)致調(diào)用了一些不同的內(nèi)部符號(hào),導(dǎo)致出現(xiàn)另外的麻煩

對(duì)于動(dòng)態(tài)庫(kù)中的日志建議采用下面的幾個(gè)方案:

動(dòng)態(tài)庫(kù)完全打自己的,日志,編譯二進(jìn)制程序不要用-rdynamic, 動(dòng)態(tài)庫(kù)鏈接的編譯加上 -Wl,-Bsymbolic 參數(shù) , 鏈接ullib, 在動(dòng)態(tài)庫(kù)中自己open,自己控制等級(jí) 1. 動(dòng)態(tài)庫(kù)不鏈接ullib, 編譯二進(jìn)制程序用-rdynamic , 這樣可以正確的使用主程序中的日志庫(kù),也規(guī)避了版本不一致帶來(lái)的問(wèn)題, 但是這樣失去了對(duì)于動(dòng)態(tài)庫(kù)日志的控制, 而且存在升級(jí)的不便, 日志的升級(jí)是由主程序控制的。

小提示:

有關(guān)動(dòng)態(tài)庫(kù)使用的例子還可以參考 SoTips 在運(yùn)行期可以通過(guò)設(shè)置環(huán)境變量LD_DEBUG查看每個(gè)符號(hào)具體鏈接到了什么地方,每個(gè)符號(hào)具體的查找過(guò)程和綁定過(guò)程.可以這樣使用 export LD_DEBUG=help 隨便運(yùn)行一個(gè)程序就可以看到對(duì)于LD_DEBUG的使用說(shuō)明

export LD_DEBUG=files./main 可以看到整個(gè)裝載過(guò)程

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

總結(jié)

以上是生活随笔為你收集整理的linux 编译查看链接库详情,Linux环境下的编译,链接与库的使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。