[英]Linking a shared library in executable vs. another shared lib
tl; dr
如果庫是通過可執行文件或其他共享庫鏈接的,則linux加載和鏈接共享庫的方式是否有所不同?
背景
假設我有一個共享庫(例如libA.so
),其中包含一個帶有靜態std::map
和一組單例類。 每個單例類都可以訪問地圖,並將自身的實例靜態添加到地圖。
有兩種情況:
libA.so
)從全局映射中讀取所有已注冊的類。 libB.so
)中使用共享庫( libA.so
),並在可執行文件中使用這個新庫。 在這種情況下, libB.so
使用libA.so
的映射為可執行文件提供某些功能(例如外觀)。 問題
如果我在可執行文件中使用(即鏈接)此共享庫(場景1),則上述映射包含單例類的列表, 但是 ,如果我在另一個共享庫中使用此庫,然后在可執行文件中使用新的共享庫(場景1) 2),地圖似乎是空的。
在這兩種情況下,我似乎都無法理解鏈接器如何處理共享庫。
更新資料
因為它變成了libB.so
不鏈接到libA.so
正確,即使使用的明確指示-lA
的標志g++
。 雖然我不能看到libA.so
通過鏈接libB.so
使用ldd
, pmap
或objdump
,我使用的類時,沒有得到運行時錯誤libA.so
。 如果使用clang++
運行相同的命令,則可以看到列出了所有必需的庫。
Drepper的論文“ 如何編寫共享庫”是該主題的很好參考,應該回答您的問題。
您應該確保在第二種情況下,庫僅鏈接一次(例如,使用完全相同的路徑)。 參見ld-linux(8)並使用例如LD_DEBUG
等...
您可能還會strace
執行以了解發生了什么。
並且您應該檢查(使用pmap
或使用cat /proc/$ThePid/maps
)該庫僅加載一次。
我將描述一種可能產生您所看到的行為的方案。
另一種情況:
libB.so
中讀取映射,則可能在任何對象有機會注冊自身之前調用它。 通常,不能保證從不同的翻譯單元(當然也不能從不同的共享庫)執行全局構造函數的順序。
上面第一個問題的解決方案是為地圖使用單例樣式模式,以便在使用時進行初始化,而不是通過全局構造函數進行初始化。
TheMap & GlobalMap () {
static TheMap instance;
return instance;
}
上面第二個問題的解決方案是禁止從全局構造函數訪問全局地圖。 也就是說,將libB.so
所有全局構造函數更改為在使用時進行初始化,而不是在全局構造函數中進行初始化。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.