Почему .lib, скомпилированный в VS2003, не может связываться с кодом, скомпилированным с VS2008?

У нас только что был интересный опыт попытки связать набор кода, скомпилированный с помощью Visual Studio Express 2008, с .lib, скомпилированным с помощью Visual Studio 2003. Все на C ++. Если быть точным, это было ядро ​​SystemC 2.2.0, которое было скомпилировано в VS2003 в .lib, и модель SystemC. который был скомпилирован в VS2008.

При связывании мы продолжали получать ошибку, что несколько символов из файла SystemC.lib (т. Е. Скомпилированных в VS2003) не были найдены во время связывания. Мы получаем следующую ошибку (в нескольких вариантах):

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

Копаясь из различных источников, выяснилось, что функция, которую ожидал найти .lib, была следующей:

Undecoration of :- "?_Xran@_String_base@std@@QBEXXZ"
is :- "public: void __thiscall std::_String_base::_Xran(void)const "

В то время как файл библиотеки, с которым VS2008 пытался связать (libcpmt.lib), использовал другое соглашение о вызовах:

Undecoration of :- "?_Xran@_String_base@std@@SAXXZ"
is :- "public: static void __cdecl std::_String_base::_Xran(void)"

Я попытался выяснить, почему возникла эта несовместимость, но в конце концов я сдался, перекомпилировал тот же самый проект Visual Studio в VS2008 и использовал этот SystemC.lib вместо файла из VS2003. Теперь все работало отлично.

Итак, основной вопрос здесь: что изменилось с VS2003 на VS2008, что заставило бы некоторые функции изменить свои соглашения о вызовах? И есть ли какой-то волшебный флаг, который можно передать компоновщику в VS2008 для использования какой-либо другой библиотеки, где функции имеют то же соглашение о вызовах, что и в компиляции VS2003?

Обновление, сводка ответов на данный момент: очень вероятно, что Microsoft изменит ABI C ++ (не C, просто C ++) с одной основной версии Visual Studio на другую. Также могут быть другие изменения в библиотеках, вызывающие несовместимость. Лучший совет - перекомпилировать .lib для каждой версии VS. По сути, просто отправьте его пользователям в исходном виде и попросите их скомпилировать его локально, используя любую версию VS, которую они установили.

Основная проблема была обнаружена с помощью рекомендаций в:

Обратите внимание, что эти вопросы не дали ответа на этот вопрос:


person jakobengblom2    schedule 13.08.2009    source источник
comment
вопрос в том, почему он не должен потерпеть неудачу? :)   -  person JohnIdol    schedule 13.08.2009
comment
своего рода естественная реакция, правда?   -  person jakobengblom2    schedule 13.08.2009


Ответы (2)


Для 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++/x.x/bits/basic_string)

person yves Baumes    schedule 13.08.2009
comment
Это, безусловно, хороший момент. Это делает досадно невозможным связать код, скомпилированный с помощью MinGW, или какой-либо другой код с VS-скомпилированным кодом любого вида. Думаю, я просто надеялся, что MS будет более последовательной в разных версиях. По сути, конечный результат состоит в том, что вам нужно создавать файлы __cdecl, используя extern C {}, вокруг всех объявлений, чтобы быть переносимыми. - person jakobengblom2; 13.08.2009

Насколько мне известно, эти проблемы возникают из-за библиотеки CRT, они меняются в основных выпусках, и вам не следует смешивать типы CRT (многопоточные, отладочные, выпускные, статические, динамические и т. Д.).

Обычно их можно свести к минимуму, динамически связавшись с CRT, мне удалось повторно использовать библиотеки VS2003 в VS2005, но это раздражает, лучше просто перекомпилировать все это. Иногда можно обойтись без флага компилятора / NODEFAULTLIB, чтобы избежать связывание с определенной библиотекой CRT, вызывающей проблемы.

person Diaa Sami    schedule 13.08.2009