Нерешенный внешний кошмар
Привет ветераны индустрии,
Я - младший в колледже, начинаю свою первую летнюю стажировку по программированию, и я нахожусь над моей головой. Компания, в которой я работаю, приобрела колоссальное приложение у другой компании, которая медленно расширялась и модифицировала его с начала 90-х годов. Решение содержит более 200000 строк кода, которые распределены по более чем 300 файлам. Полное решение было написано в соответствии со стандартами ANSI-C++. Код почти полностью недокументирован, и большинство из них выглядит для меня как иероглифы. В конечном счете, моя работа заключается в переносе этого кода на встроенный Linux. В настоящее время моя работа заключается в том, чтобы просто собрать его с помощью Visual Studio 2008 на Windows XP.
Сегодня я сталкиваюсь с ошибками компоновщика, такими как эта:
libcmtd.lib(sprintf.obj) : error LNK2005: _sprintf already defined in msvcrtd.lib(MSVCR90D.dll)
Насколько я понимаю, это часто происходит, когда разные проекты в рамках решения компилируются с использованием разных библиотек времени выполнения. В моем решении 6 проектов. 4 из них были настроены на компиляцию с использованием многопоточной библиотеки DLL отладки (/MDd), один из них был настроен на компиляцию с использованием многопоточной библиотеки отладки (/MTd), а один из них был настроен на компиляцию с использованием многопоточная библиотека времени выполнения dll (/MD). Первое, что я попытался получить после получения этого сообщения об ошибке, это изменить параметры / MTd и / MD на / MDd, чтобы все компилировалось с теми же библиотеками времени выполнения. К сожалению, это привело к следующей ошибке в afx.h:
fatal error C1189: #error : Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version. Please #define _AFXDLL or do not use /MD[d]
Немного покопавшись, я обнаружил, что он уже сказал мне, что мне нужно делать. Я пошел дальше и изменил параметр "Использование MFC" в "Свойства проекта" -> "Свойства конфигурации" -> "Общие" на "Использовать MFC в общей библиотеке DLL". В этот момент я начал получать десятки неразрешенных внешних ошибок, таких как эти:
dataPropertySheet.obj : error LNK2019: unresolved external symbol "public: __thiscall CResizableSheet::CResizableSheet(unsigned short const *,class CWnd *,unsigned int)" (??0CResizableSheet@@QAE@PBGPAVCWnd@@I@Z) referenced in function "public: __thiscall CdataPropertySheet::CdataPropertySheet(unsigned short const *,class CWnd *,unsigned int)" (??0CdataPropertySheet@@QAE@PBGPAVCWnd@@I@Z)
ResizableLib.lib(ResizablePage.obj) : error LNK2001: unresolved external symbol "public: virtual int __thiscall CWnd::Create(char const *,char const *,unsigned long,struct tagRECT const &,class CWnd *,unsigned int,struct CCreateContext *)" (?Create@CWnd@@UAEHPBD0KABUtagRECT@@PAV1@IPAUCCreateContext@@@Z)
Прочитав страницы MSDN на LNK2001 и LNK2019, я понял, что понятия не имею, что происходит. Это не те вопросы, которым они учили нас, как иметь дело в школе. Я знаю свои структуры данных, и это все. Как я оказался там, где я сейчас, выше меня!
Из моих ограниченных знаний кажется, что различные версии этих модулей для отладки и выпуска запутаны в сети директив препроцессора и #include. Существует множество вложенных проверок #ifdef и операторов #define, которые выполняются почти во всех заголовках и исходных файлах по всему решению для переменных среды, имен файлов, макросов и, возможно, многого другого. Внося даже небольшие изменения в настройки моего компилятора, я, кажется, перенаправляю большие части программы в разные библиотеки, которые имеют очень разные определения функций. Это мое смутное концептуальное понимание происходящего.
Я чувствую, что мне нужно лучшее понимание того, как работает этот код, прежде чем у меня появится шанс устранить эти ошибки компилятора. С этой целью я пытался построчно пройтись по многим файлам, чтобы увидеть, куда они ведут, какие объекты и переменные находятся в области видимости и так далее. К сожалению, это не дает мне слишком далеко, потому что каждый вызов внешней функции неоднозначен, и у меня нет никакого способа просмотреть беспорядок препроцессора, чтобы узнать, какая версия любой данной функции должна вызываться.
Я искал магические решения, чтобы наметить программу и попытаться понять ее. Я попробовал один под названием Doxygen, но либо я не знаю, как правильно его использовать, либо он так же запутался в препроцессоре, как и я.
У меня вопрос такой:
Каковы мои оставшиеся варианты?
На данный момент это между:
а.) Переключение основных специальностей
б.) спрыгнуть с моста
Ни один из этих вариантов не поможет мне лучше понять эту кодовую базу и получить ее компиляцию. У кого-нибудь есть идеи получше? Подобные переживания? Мудрецом поделиться мудростью?
Благодаря тонну,
для -Alex-
3 ответа
Скомпилируйте все с теми же библиотеками времени выполнения. Конец истории.
Похоже, вы используете CResizableSheet и CResizeablePage из CodeProject. Если вы используете скомпилированную статическую библиотеку с этой страницы, вы можете попробовать загрузить исходный код и скомпилировать его с параметром соответствия /MDd и использовать.lib, который он выводит в разделе ввода компоновщика вашего проекта. Я также предложил бы выполнить очистку всех (перейдите в build->batch build->select all, затем нажмите clean) и затем попробуйте выполнить сборку еще раз, чтобы убедиться, что все обновлено.
Я слышал, что уход - отличная программа...
С риском быть педантичным, вы боретесь с ошибками компоновщика, а не с ошибками компилятора. Мой основной подход к этому состоит в том, чтобы создать новое решение и начать добавлять проекты по одному, заставляя каждый строить по очереди.
Я бы также серьезно подумал о том, чтобы попытаться максимально стандартизировать настройки каждого проекта. Самый простой способ сделать это - создать пустые проекты в вашем новом решении и скопировать в них существующий код.
Для начала вы должны принять следующие настройки (связанные с MFC):
Отладка: использование MFC в общей DLL, / MDd
Release: использовать MFC в общей DLL, / MD
MDd и MD - это один и тот же режим, но один из них связан с библиотеками отладки с дополнительной информацией для отладки.
Тогда все, что вы можете сделать, это работать над одним проектом за раз. Обратите внимание, что если вы создаете новое решение в соответствии с предложением, вам необходимо перестроить дерево зависимостей между проектами. (Щелкните правой кнопкой мыши по проекту и выберите "Зависимости", вы поймете, что я имею в виду.)
Когда вы сталкиваетесь с проблемами при этом, вы должны подружиться со старшим разработчиком на вашем рабочем месте =).