Ошибка 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, чтобы точно знать, куда она идет.

Другие вопросы по тегам