在 linux 下編寫動態鏈結庫程式,需要注意 dll 之間的符號衝突。
當我們鏈結庫需要提供給很多方整合使用,需要面對複雜的整合環境,其中乙個大問題就是與第三方整合環境的符號衝突。
這些衝突有些不是通過嚴格控制名字空間解決的,比如當我們使用了一些開源庫,我們不清楚第三方整合環境有沒有這些庫,即使有是不是版本匹配,我們也不想對第三方整合環境提太多要求,這會增加整合成本。在這種情況下,我們會將這些開源庫靜態鏈結到我們的動態鏈結庫中,僅提供乙個 so 檔案。但是這樣做不足以避免符號衝突。
linux 下的動態鏈結機制允許多個 so 庫定義相同的符號,不會在構建時出現符號重複定義錯誤。這種衝突在執行時也不會出現錯誤警告資訊,執行時鏈結過程一般使用重複定義的符號中最早出現的版本,除非明確使用 dlsym 系統 api 獲取。
因此,在執行時,到底會繫結到那個版本的符號上,是不確定的事。這種衝突是雙向的,我們的鏈結庫可能錯誤使用了第三方整合環境的符號版本,另一方面,第三方環境也可能錯誤繫結我們的鏈結庫中的開源庫的符號版本。
解決衝突的方法是將我們使用的開源庫裡面的符號隱藏起來。程式構建分為編譯和鏈結兩步,在這兩步都有隱藏符號的方法。
在編譯階段,可以指定符號的可見屬性 __attribute__ ((visibility("hidden"))),比如:
void func() __attribute__ ((visibility("hidden")));
但是我們不可能對所有符號乙個個新增可見屬性,所以 gcc 提供了 -fvisibility=hidden 編譯 flag,可以設定所有符號都隱藏。此時,需要為應該匯出的符號明確可見屬性,比如:
void export_func() __attribute__ ((visibility("default")));
在鏈結階段,可以通過 version script 檔案將符號分為 local、global 兩類。要匯出的符號歸於 global 類。如我們建立檔案 mylib.ver,內容為:
{global:
export_func;
Linux 動態鏈結庫 so 的使用
1.背景 庫 就是已經編寫好的,後續可以直接使用的 c 靜態庫 會合入到最終生成的程式,使得結果檔案比較大。優點是不再有任何依賴。c 動態庫 動態庫,乙個檔案可以多個 同時使用記憶體中只有乙份,節省記憶體,可以隨主 一起編譯。缺點是需要標頭檔案。說 庫就是除了main函式之外的其他 都可以組成庫。2...
linux下檢視動態鏈結庫so檔案的依賴的相關組建
我們很多c程式在windows下是以dll形式展現的,在linux則是以so 形式展現的。windows一般不會因為編譯dll檔案的編譯器版本不同而出先dll檔案不能執行。但是linux下,不同版本核心的linux下編譯的c程式,在其他版本的linux下就容易出現無法執行的問題。主要可能是支援程式的...
linux下檢視動態鏈結庫so檔案的依賴的相關元件
我們很多c程式在windows下是以dll形式展現的,在linux則是以so 形式展現的。windows一般不會因為編譯dll檔案的編譯器版本不同而出先dll檔案不能執行。但是linux下,不同版本核心的linux下編譯的c程式,在其他版本的linux下就容易出現無法執行的問題。主要可能是支援程式的...