2009-02-06 46 views
12

我試圖用visual studio 2005構建一個C/C++靜態庫。由於運行時庫的選擇是一個編譯選項,我不得不構建我的庫的四個變體,每個變體的運行時庫:爲什麼運行時庫是編譯器選項而不是鏈接器選項?

  • /MT - 靜態運行時庫
  • /MD - DLL運行時庫
  • /MTD - 靜態調試運行時庫
  • /MDD - 調試DLL運行時庫

這些是編譯器選項,而不是鏈接器選項。來自Linux背景,這似乎很奇怪。不同的運行時庫有不同的調用約定或什麼?爲什麼不能在鏈接時解析不同的運行時庫,即當我鏈接使用靜態庫的應用程序時?

+0

雖然似乎有很好的理由給出了答案 - 我同意你的看法。我總是最終在錯誤的地方尋找這個設置。與預編譯頭文件設置相同 - 它有自己的類別,而不是在預處理器部分。 – 2009-02-07 06:23:55

回答

7
該zdan提到像 _DLL_DEBUG C預處理器的定義的

一個副作用:

一些數據結構(如STL容器和迭代器)可以具有不同的尺寸在調試運行時,可能是由於功能,如_HAS_ITERATOR_DEBUGGING_SECURE_SCL。您必須使用structure definitions that are binary-compatible with the library you're linking to編譯您的代碼。

如果混合使用,並且被編譯不同的運行時庫匹配的目標文件,你會得到鏈接器警告,如下所示:

warning LNK4098: defaultlib 'LIBCMT' conflicts with use of other libs 
0

我相信這背後的原因是SEH(結構化異常處理程序)代碼將根據鏈接到哪個運行時庫以不同的方式生成。

1

如果您忽略靜態運行時,那麼您將獲得與Linux相同的選項。

我知道靜態運行時可能是有用的,但我從來沒有真正需要它。此外,它會導致潛在的問題,處理分配/釋放內存,因此我發現使用DLL運行時更容易。

儘管Release/Debug版本與Linux/Unix相同。
儘管爲了提高效率,我的理由是我建立了一個單線程和多線程版本的庫。

8

這些選項可能會添加在運行時庫頭文件中使用的定義(例如__DLL和_​​_DEBUG)。一個常見的事情是動態鏈接時將__declspec(dllimport)添加到函數聲明中。

編譯器似乎也使用這些來幫助鏈接器鏈接到正確的庫。這在MSDN中有解釋。

3

編譯器需要知道您是否生成單線程或多線程代碼。編譯器默認生成線程安全代碼(多線程)。你必須告訴它是否需要單線程代碼。如果你改變默認值,編譯器會改變默認的運行時庫(你可以在鏈接器命令選項中覆蓋它,只要確保你選擇的庫具有相同的代碼結構作爲你的目標文件:單線程靜態,多線程靜態或多線程DLL)。請注意,沒有單線程DLL選項(根據定義,運行時庫DLL將作爲線程安全構建,因爲它由多個應用程序共享)。

+1

此外,不再有單線程靜態運行時(我不知道這是否啓動VC2005或VC2008)。 – 2009-02-09 01:12:40

0

沒有爲DLL的和靜態庫生成不同的機器代碼。

而在Linux上你也必須這樣做,如果你想建立一個共享庫,編譯器標誌被稱爲-fPIC。否則,在AMD64和SPARC(也可能是其他)上將會崩潰。在i386架構上,鏈接器足夠聰明,不會在內存中共享庫,因此不會崩潰。

相關問題