2015-07-03 208 views
2

我有以下設置:靜態庫鏈接兩次

  1. 靜態庫
  2. 鏈接到鏈接到(1)(1)
  3. 的可執行文件和動態庫( 2.)

來自靜態庫的代碼現在被複制並存在於動態庫和可執行文件中。

問題:

是數據(全局變量,靜態類成員)也複製並執行可執行文件和DLL看到相同的數據?

Linux和Windows之間有區別嗎?

你會如何解決這個問題?

編輯:

感謝您的答案,我無法解釋我的情況下發生的事情完全一樣。

靜態庫沒有導出/導入標誌。 動態庫帽子導出自己的符號。

的Windows:

動態庫有靜態庫的文本+數據segement的副本。 可執行程序無法知道動態庫是否鏈接了靜態庫,因爲靜態庫符號的非外部可見。

的Linux:

動態庫有靜態庫的文本數據segement的副本。 雖然動態庫包含靜態庫中的所有符號(文本和數據),但它們在其自己的符號表中。 - >可執行文件看到,動態庫已經定義了靜態庫的所有符號,並且沒有重新定義它們。

這很糟糕,因爲您通常需要在Linux和Windows上使用相同的行爲。

  1. 分享符號(在Linux默認)

    • 上所有的符號連接起來,共享庫時,添加DLL導出命令,從靜態庫。 __attribute__ ((dllexport))
    • 將靜態庫鏈接到可執行文件時添加一個dll導入命令。__attribute__ ((dllimport))
    • 的代碼和數據只存在於共享庫,並從外面
  2. Reduntant符號可鏈接(在Windows默認)

    • 你需要確保的符號靜態庫不包含在共享庫的符號表中
    • __attribute__ ((visibility ("hidden"))) on gcc
    • 當鏈接可執行文件時,來自靜態li brary不能在任何地方找到,所以他們再次被包括在內。
+1

是的,數據是重複的。你可以通過使用動態庫來解決它。 – UmNyobe

+0

@UmNyobe:已經有一個DLL;創造另一個將是沒有幫助的,因爲它不會與第一個共享全球數據。 –

+0

庫是否預編譯或可用作源代碼? –

回答

4

據我所知,這取決於操作系統(因爲C++語言沒有說太多關於圖書館應該如何工作)。

在Windows上,你會得到兩倍的代碼和數據,而這更糟糕的所有兩次全球在該庫中聲明的變量(!)

這個問題靜態鏈接標準庫中時顯示出來一個程序和一個使用它的庫,當你得到兩個默認分配器時,如果你在庫上調用new,而在另一個上調用delete,那麼該對象將在new一側泄漏,並且堆在delete一側可能會損壞。

我不知道其他操作系統的細節,但我希望類似的問題可能會出現

+0

+1新增/刪除技巧:我在過去遭受過這種情況,很快就學會了避免使用異構構建。 –

+0

如果所有庫調用都是_functional_(即它們沒有觀察或修改任何全局狀態),則可以使用靜態鏈接,因爲代碼可能更有效/更小(僅包含您使用的符號),在所有其他情況下,我建議反對它 – pqnet

+0

似乎在Linux上以某種方式不復制數據。 http://stackoverflow.com/questions/4925233/global-variable-has-multiple-copies-on-windows-and-a-single-on-linux-when-compil – dari

0

IMO這是一個討厭的情況,因爲有兩個可執行文件(exe文件和DLL),各自有各自的實例代碼和全局數據。它們是獨立構建的,無法共享其內存映射。

一個選項可以讓dll公開靜態庫的必需成員,以便exe可以直接鏈接到它們。

+0

我理解你的答案是否正確:在dll中重新聲明靜態庫中的所有變量和函數,以便可執行文件不必鏈接到靜態庫。 – dari

+0

是的,這就是我的意思,希望鏈接器會同意。該庫的頭文件將存在三個版本:編譯靜態的標準,導出爲構建DLL和EXE導入。 –