4

我們剛剛嘗試鏈接使用Visual Studio Express 2008編譯的代碼集與使用Visual Studio 2003編譯的.lib時的有趣體驗。所有內容都在C++中。確切地說,它是在VS2003中編譯爲.lib的SystemC 2.2.0內核,以及在VS2008中編譯的SystemC模型。爲什麼在VS2003中編譯的.lib無法與使用VS2008編譯的代碼鏈接?

鏈接時,我們不斷收到在鏈接過程中沒有找到SystemC.lib文件中幾個符號(即在VS2003中編譯)的錯誤。我們得到正的錯誤是這樣的(在幾個變種):

SystemC.lib(sc_port.obj) : error LNK2001: unresolved external symbol "public: vo 
id __thiscall std::_String_base::_Xran(void)const " ([email protected][email protected]@@QB 
EXXZ) 

從各種線索挖,原來該功能預計將找到的.lib是這樣的:

Undecoration of :- "[email protected][email protected]@@QBEXXZ" 
is :- "public: void __thiscall std::_String_base::_Xran(void)const " 

雖然這VS2008試圖用(libcpmt.lib)鏈接庫文件使用不同的調用約定:

Undecoration of :- "[email protected][email protected]@@SAXXZ" 
is :- "public: static void __cdecl std::_String_base::_Xran(void)" 

我試圖找出爲什麼這個不兼容的發生,但最終我放棄了,recompil編輯VS2008中完全相同的Visual Studio項目,並使用該SystemC.lib代替VS2003中的那個。現在,事情完美無缺。

所以這裏的根本問題是:什麼從VS2003變成VS2008會導致一些功能改變他們的調用約定?是否有一些神奇的標誌給VS2008中的鏈接器使用其他函數具有相同的調用約定在VS2003編譯的其他庫?

更新,到目前爲止的答案摘要:Microsoft很可能會將C++(不是C,只是C++)ABI從一個主要版本的Visual Studio更改爲下一個。庫中還可能存在導致不兼容的其他更改。最好的建議是爲每個版本的VS重新編譯.lib。從本質上講,只需將它在源代碼中發佈給用戶,並讓他們使用它們碰巧安裝的任何版本的VS進行本地編譯。

的基本問題是通過使用建議發現:

注意,這些問題沒有回答這個問題:

+2

問題是'爲什麼它不會失敗?' :) – JohnIdol 2009-08-13 14:01:01

+0

那種自然的反應吧? – jakobengblom2 2009-08-13 14:09:46

回答

3

C++ ABI沒有標準。這意味着所有的C++編譯器都可以處理不同的ABI,並且包含與同一編譯器不同的版本。您可能會遇到來自Gcc的兩個不同主要版本的相同問題。 當他們找到改善鏈接步驟的方法時,可能會發生這種修改。

但ABI涉及更多的那。例如,vtable的存儲方式由編譯器生成的代碼進行處理。如果它發生變化,那麼2008年生成的對象和代碼將不會與預計2003年完成的方式兼容。

在這一點上,你可以理解爲什麼C++庫或者隨其源代碼一起提供,或者在不同的體系結構和編譯器上編譯。

通常在編寫庫時,爲了避免出現這樣的問題,可以用C語言開發它,而不是C++。由於C帶有一個標準化的ABI,您可以用一個編譯器編譯它,然後將該庫與任何C編譯器連接,並尊重C ABI標準。 例如字符串被實現的方式是標準的,並且可能永遠不會移動(臭名昭着的以空字符結尾的字符串)。 雖然std :: string實現從一個Gcc主要版本更改爲另一個(只需看一下basic_string類中的/ usr/include/C++/xx/bits/basic_string文件)

+1

這當然是一個好點。這使得連接MinGW編譯的代碼或任何類型的VS編譯代碼變得不可能。我想我只是希望MS能夠在各個版本之間更加一致。實質上,最終的結果是你必須使用extern「C」{}來執行__cdecl文件,使得所有的聲明都是可移植的。 – jakobengblom2 2009-08-13 17:25:44

2

據我所知由於CRT庫發生問題,它們隨主要版本而變化,並且不應混用CRT類型(多線程,調試,發佈,靜態,動態等)。

通常他們可以通過動態鏈接到CRT來最小化,我曾經成功地重複使用VS2005中的VS2003庫,但它很煩人,最好是重新編譯整個事情。 有時,您可以通過使用/NODEFAULTLIB編譯器標誌避免與某個導致問題的CRT庫鏈接。