Ошибка LNK2001 при компиляции приложений, ссылающихся на STLport-5.1.4 с VC++ 2008
Заранее прошу прощения за длинный пост...
Раньше я имел возможность создавать наши решения VC++ (мы на VS 2008), когда мы перечисляли каталоги включений и библиотек STLPort в меню VS Menu > Инструменты> Параметры> Каталоги VC++> Каталоги для файлов включений и библиотек. Однако мы хотели перейти к процессу сборки, который полностью основан на файлах.vcproj и.sln. Они могут быть проверены в системе контроля версий в отличие от VS Options, которые должны быть настроены на каждом ПК для разработки отдельно. Мы обработали переход для большинства библиотек, добавив каталоги "Включить" на страницах свойств каждого проекта> Свойства конфигурации> C/C++ > Общие> Дополнительные каталоги включения и "Библиотеки" в "Линкер"> "Общие"> "Дополнительные каталоги библиотеки".
К сожалению, этот подход не работает для STLPort. Мы получаем ошибки LNK2019 и LNK2001 во время связывания:
Error 1 error LNK2019: unresolved external symbol "public: virtual bool __thiscall MyClass::myFunction(class stlp_std::basic_istream<char,class stlp_std::char_traits<char> > &,class MyOtherClass &,class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > &)const " (?myFunction@MyClass@@UBE_NAAV?$basic_istream@DV?$char_traits@D@stlp_std@@@stlp_std@@AAVSbprobScenarioData@@AAV?$basic_string@DV?$char_traits@D@stlp_std@@V?$allocator@D@2@@3@@Z) referenced in function _main MyLibrary.obj
Error 5 error LNK2001: unresolved external symbol "public: static void __cdecl MyClass::myFunction(class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > const &,class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > const &,class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > const &,class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > const &,long,enum MyClass::MessageType,int,class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > const &)" (?myFunction@MyClass@@SAXABV?$basic_string@DV?$char_traits@D@stlp_std@@V?$allocator@D@2@@stlp_std@@000JW4MessageType@1@H0@Z) MyLibrary.lib
Это происходит при связывании и выполнении проекта с зависимостями, которые являются проектами библиотеки. Любопытно, что этого не происходит при связывании самих библиотечных проектов. Есть идеи?
6 ответов
Раймонд Чен недавно говорил об этом в The Old New Thing- одна из причин этих проблем состоит в том, что библиотека была скомпилирована с одним набором переключателей, но ваше приложение использует другой набор. Что вам нужно сделать, это:
Получите точный символ, который ищет компоновщик. Это будет ужасное искалеченное имя. Используйте шестнадцатеричный редактор (IIRC, Visual Studio сделает это), чтобы посмотреть.lib-файл, на который вы ссылаетесь. Найдите символ, который почти то, что ищет компоновщик, но не совсем. Учитывая различия в символах, попытайтесь выяснить, какие ключи командной строки помогут. Удачи - для людей, которые не привыкли к такого рода проблемам, решение может занять дни, чтобы выяснить (!)
Как упоминалось в других ответах, это ошибка компоновщика и, вероятно, результат компиляции библиотеки и приложения с различными параметрами. Есть несколько решений для отслеживания этого уже (одно из них в качестве выбранного ответа, в настоящее время). Эти решения будут работать. Однако есть несколько инструментов, которые значительно упростят ваш поиск.
Для начала, понимание украшенных имен поможет. Во всем этом мусоре вы узнаете некоторые вещи: имя вашей функции, пространства имен, некоторые типы классов, которые вы используете. Все эти символы вокруг них что-то значат для компилятора, но вам не нужен компилятор, чтобы сказать вам, кто они.
Введите undname.exe:
undname.exe <украшенное имя>
- простая программа командной строки, которая находится в вашем каталоге VS bin.
- принимает украшенное имя в качестве первого аргумента.
- выводит читабельный формат символа.
Вооружившись этими знаниями, теперь вы можете перейти к поиску разумного кандидата на неправильно созданный символ.
Во-первых, вы можете редактировать свои библиотеки в шестнадцатеричном редакторе, как это предлагается в другом месте. Тем не менее, есть гораздо более простой способ найти символы.
Введите dumpbin.exe:
dumpbin.exe <переключатели> <имя библиотеки>
- простая программа командной строки, которая находится в вашем каталоге VS bin.
- принимает набор переключателей и библиотеку для их применения.
- выводит информацию из библиотеки
Переключатель, который вас заинтересует для вашего вопроса, - / linkermember. Есть много других переключателей, которые могут дать вам очень интересную информацию, но этот перечислит все символы в библиотеке.
На данный момент, немного подкованных командной строки будет служить вам хорошо. Такие инструменты, как grep, действительно могут сократить рабочий цикл, но вы можете обойтись путем перенаправления в файл и использования блокнота или чего-то подобного.
Так как у меня нет твоего кода или библиотеки, я придумаю пример из TinyXML.
Предполагая, что ваше сообщение об ошибке было так:
Error 1 error LNK2019: unresolved external symbol "public: unsigned char __cdecl TiXmlComment::Accept(bool,class TiXmlVisitor *) " (?Accept@TiXmlComment@@ZBE_NPAVTiXmlVisitor@@@Z) referenced in function _main MyLibrary.obj
Определив, что это функция в TinyXML, я могу начать искать несоответствующий символ. Я начну со сброса членов библиотеки. (Обратите внимание, что переключатель в единственном числе, это всегда заставляет меня печатать его по памяти!)
>dumpbin /linkermember tinyxml.lib
Microsoft (R) COFF/PE Dumper Version 8.00.50727.762
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file tinyxml.lib
File Type: LIBRARY
Archive member name at 8: /
4992E7BC time/date Wed Feb 11 08:59:08 2009
uid
gid
0 mode
B402 size
correct header end
859 public symbols
16292 ??$_Allocate@D@std@@YAPADIPAD@Z
16292 ??$_Char_traits_cat@U?$char_traits@D@std@@@std@@YA?AU_Secure_char_traits_tag@0@XZ
16292 ??$copy_s@U?$char_traits@D@std@@@_Traits_helper@std@@YAPADPADIPBDI@Z
16292 ??$copy_s@U?$char_traits@D@std@@@_Traits_helper@std@@YAPADPADIPBDIU_Secure_char_traits_tag@1@@Z
16292 ??$move_s@U?$char_traits@D@std@@@_Traits_helper@std@@YAPADPADIPBDI@Z
16292 ??$move_s@U?$char_traits@D@std@@@_Traits_helper@std@@YAPADPADIPBDIU_Secure_char_traits_tag@1@@Z
16292 ??$use_facet@V?$ctype@D@std@@@std@@YAABV?$ctype@D@0@ABVlocale@0@@Z
16292 ??0?$_String_val@DV?$allocator@D@std@@@std@@IAE@V?$allocator@D@1@@Z
16292 ??0?$_String_val@DV?$allocator@D@std@@@std@@QAE@ABV01@@Z
Это, очевидно, слишком много, чтобы читать, но нам не нужно, мы знаем, что мы ищем, поэтому мы просто будем искать это.
>dumpbin /linkermember tinyxml.lib | grep Accept
529AE ?Accept@TiXmlComment@@UBE_NPAVTiXmlVisitor@@@Z
529AE ?Accept@TiXmlDeclaration@@UBE_NPAVTiXmlVisitor@@@Z
529AE ?Accept@TiXmlDocument@@UBE_NPAVTiXmlVisitor@@@Z
529AE ?Accept@TiXmlElement@@UBE_NPAVTiXmlVisitor@@@Z
529AE ?Accept@TiXmlText@@UBE_NPAVTiXmlVisitor@@@Z
529AE ?Accept@TiXmlUnknown@@UBE_NPAVTiXmlVisitor@@@Z
3 ?Accept@TiXmlComment@@UBE_NPAVTiXmlVisitor@@@Z
3 ?Accept@TiXmlDeclaration@@UBE_NPAVTiXmlVisitor@@@Z
3 ?Accept@TiXmlDocument@@UBE_NPAVTiXmlVisitor@@@Z
3 ?Accept@TiXmlElement@@UBE_NPAVTiXmlVisitor@@@Z
3 ?Accept@TiXmlText@@UBE_NPAVTiXmlVisitor@@@Z
3 ?Accept@TiXmlUnknown@@UBE_NPAVTiXmlVisitor@@@Z
Это намного легче читать. Глядя на нашу ошибку, мы ищем функцию принятия TiXmlComment. Мы могли бы получить дополнительный вывод для этого имени, если бы у нас было много совпадений (как, например, просмотр функции размера в stl!), Но в этом случае мы можем выбрать его из списка. Здесь мы обращаемся к имени:
>undname ?Accept@TiXmlComment@@UBE_NPAVTiXmlVisitor@@@Z
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation. All rights reserved.
Undecoration of :- "?Accept@TiXmlComment@@UBE_NPAVTiXmlVisitor@@@Z"
is :- "public: virtual bool __thiscall TiXmlComment::Accept(class TiXmlVisitor *)const "
Итак, в этом примере наше приложение ищет функцию, которая возвращает неподписанный символ, но в библиотеке есть функция, возвращающая тип bool.
Это надуманный пример, но он иллюстрирует технику, которая используется для отслеживания вашей проблемы. Вы, вероятно, ищете тип typedef, который устанавливается по-разному в зависимости от ваших параметров.
Проблема, с которой я столкнулся, была с time_t. В некоторых библиотеках, которые я использовал, time_t использовал 32-битный тип как часть своего внутреннего представления. Эта библиотека была сгенерирована с более старым компилятором, где это было по умолчанию. В VS 2005 time_t использует 64-битный тип по умолчанию. Мне пришлось добавить препроцессор определить _USE_32BIT_TIME_T, чтобы заставить его скомпилировать. Я выследил эту проблему именно так, как я описал.
Я надеюсь, что это поможет кому-то решить эту проблему!
Вы должны настроить порт STL для использования собственной реализации IOStreams.
Также есть ли какая-то конкретная причина, по которой вы используете STLPort? Реализация по умолчанию STL рекомендуется, если вы не пытаетесь создать кроссплатформенное приложение - даже тогда, в большинстве случаев, оно не очень нужно.
Эти ошибки ссылок указывают на то, что определенные классы в вашем приложении либо не были скомпилированы с использованием STLPort, либо были исключены из сборки. Они не предполагают, что вы не ссылаетесь на STLport.
Мои предположения будут такими:
- Настройки сборки для MyClass каким-то образом перезаписывают настройки всего проекта для пути включения, и, таким образом, MyClass создается с использованием стандартной реализации C++ STL, а не STLport. Это должно быть легко проверить - запустите dumpbin для объектного файла и проверьте, что функции в нем ссылаются на стандартную библиотеку в пространстве имен stlp_* или нет. Если нет, вполне вероятно, что компилятор не выбирает правильный путь включения. Я бы также взглянул на командную строку, с которой IDE вызывает компилятор. Их также можно просмотреть через свойства конфигурации C/C++.
- Как уже упоминалось в других постерах, существует вероятность того, что MyClass не создается, но это должно быть очень легко проверить.
Это ошибка ссылки. Это не связано с вашими путями включения.
Вы либо забыли добавить MyClass.cpp в свой проект, либо забыли определить эти две функции.
Причина, по которой ошибка не возникает при "связывании" библиотечных проектов, заключается в том, что библиотечные проекты не связаны. Это просто набор объектов OBJ, которые объединяются программой LIB в файл библиотеки.
Добавьте имя библиотеки в список дополнительных библиотек для ссылки. Извините, я не нахожусь перед последней версией VS, чтобы точно знать, куда она идет.