Ошибка средств компоновщика LNK2001

Обновлен: Ноябрь 2007

Сообщение об ошибке

Неразрешенный внешний символ "символ"
unresolved external symbol "symbol"

В коде присутствует ссылка на что-то (функцию, переменную, метку), что не может быть найдено компоновщиком в библиотеках или объектных файлах.

Это сообщение об ошибке сопровождается неустранимой ошибкой LNK1120.

Возможные причины

  • При обновлении управляемой библиотеки или проекта веб-сервиса из Visual C++ 2003, параметр компилятора /Zl будет добавлен на страницу свойств Командная строка. Это приведет к ошибке LNK2001. Для решения проблемы удалите параметр /Zl на странице свойств Командная строка. Дополнительные сведения см. в разделах /Zl (Опущенное по умолчанию имя библиотеки) и Открытие свойств страниц проекта. Либо добавьте файлы msvcrt.lib и msvcmrt.lib в свойство "Дополнительные зависимости компоновщика".

  • Запрашиваемое кодом не существует (например, неправильное написание символа, неверный регистр).

  • Неверный запрос кода (используется смешанная версия библиотек — из разных версий продукта).

Конкретные причины

Проблемы кодирования

  • Если в тексте отчета диагностики ошибки LNK2001 указано, что __check_commonlanguageruntime_version — это неразрешенный внешний символ, см. LNK2019.

  • Определение шаблона члена находится за пределами класса. Visual C++ имеет ограничение, заключающееся в том, что шаблоны членов должны быть полностью определены в пределах включающего класса. См. статью Q239436 в Базе знаний об ошибке LNK2001 и шаблонах членов.

  • Несоответствующий регистр в коде или файле определения мvlekz (DEF) может вызвать ошибку LNK2001. Например, если вы дали имя переменной var1 в одном исходном файле C++ и попытались получить к ней доступ, как к VAR1 в другом.

  • Проект, использующий function inlining, определяющий функции в CPP-файле, а не в файле заголовка, может вызвать ошибку LNK2001.

  • Вызов функции C из программы на C++ без использования extern "C" (который заставляет компилятор использовать соглашение о присвоении имен языка C) может вызвать ошибку LNK2001. Параметры компилятора /Tp и /Tc заставляют компилятор компилировать файлы как C++ или C, соответственно, независимо от расширения имени файла. Эти параметры могут привести к изменению имен функций.

  • Попытка создать ссылки на функции или данные, не имеющие внешних связей, может привести к ошибке LNK2001. В C++ встроенные функции и данные const имеют внутренние связи, если явно не указаны как extern.

  • Отсутствующий текст функции или переменная может вызвать ошибку LNK2001. Имея только прототип функции или объявление extern, компилятор может продолжать работу без ошибок, но компоновщик не сможет разрешить вызов по адресу или ссылке для переменной, поскольку отсутствует код функции или пространство переменной.

  • Вызов функции с типами параметров, не соответствующими указанным в объявлении, может вызвать ошибку NK2001. Дополнение к имени включает параметры функции в окончательное дополненное имя функции.

  • Некорректно включенный прототип, заставляющий компилятор ожидать текст функции, который не предоставляется, может вызвать ошибку LNK2001. Если функция F реализована и в классе, и за пределами класса, помните о правилах разрешения области C++.

  • В C++, включение прототипа функции в определение класса и невключение реализации функции для этого класса вызывает ошибку LNK2001.

  • Попытка вызова чистой виртуальной функции из конструктора или деструктора абстрактного базового класса может вызвать ошибку LNK2001. Чистая виртуальная функция не реализуется в базовом классе.

  • Попытка использования переменной, объявленной внутри функции (локальная переменная), за пределами области функции может вызвать ошибку LNK2001.

  • При построении окончательной версии проекта ATL указывает на необходимость кода запуска CRT. Для исправления ошибки выполните одно из следующих действий.

    • Удалите _ATL_MIN_CRT из определения процессора, чтобы разрешить включение кода запуска CRT. Подробные сведения см. в разделе Страница общих параметров конфигурации.

    • Если возможно, удалите вызовы функций CRT, требующие код запуска CRT. Вместо них используйте эквиваленты для Win32. Например, используйте lstrcmp вместо strcmp. Известные функции, требующие код запуска CRT, — это некоторые строчные функции и функции с плавающей запятой.

Проблемы при компилировании и компоновке

  • В проекте отсутствует ссылка на файл библиотеки (LIB) или объекта (OBJ). Подробные сведения см. в разделе Файлы LIB как вводные компоновщика.

  • Если вы используете /NODEFAULTLIB или /Zl, библиотеки, содержащие необходимый код, не будут скомпонованы в проект, если они не включены явно. (При компилировании с /clr or /clr:pure, вы увидите ссылку на .cctor; см. Инициализация смешанных сборок.)

  • Если вы используете Unicode и MFC, то у вас возникнет неразрешенный внешний _WinMain@16, если не создана точка входа для wWinMainCRTStartup; воспользуйтесь /ENTRY. См. Сводка по программированию в Юникоде.

    См. следующие статьи базы знаний, расположенные в библиотеке MSDN Library. В библиотеке MSDN щелкните выберите вкладку Поиск, укажите в поле ввода номер или заголовок статьи и нажмите Показать разделы. При поиске по номеру статьи отключите параметр Искать только в названиях.

    • Q125750   "PRB: Error LNK2001: '_WinMain@16': Unresolved External Symbol"

    • Q131204   "PRB: Wrong Project Selection Causes LNK2001 on _WinMain@16"

    • Q100639   "Unicode Support in the Microsoft Foundation Class Library"

    • Q291952    "PRB: Link Error LNK2001: Unresolved External Symbol _main"

  • Код компоновки, скомпилированный с /MT с библиотекой LIBC.lib приводит к ошибке LNK2001 в _beginthread, _beginthreadex, _endthread и _endthreadex.

  • Код компоновки, требующий многопотоковые библиотеки (любой код MFC или код, скомпилированный с /MT), вызывает ошибку LNK2001 в _beginthread, _beginthreadex, _endthread и _endthreadex. Дополнительные сведения см. в следующей статьях базы знаний:

    • Q126646 "PRB: Error Msg: LNK2001 on __beginthreadex and __endthreadex"

    • Q128641 "INFO: /Mx Compiler Options and the LIBC, LIBCMT, MSVCRT Libs"

    • Q166504 "PRB: MFC and CRT Must Match in debug/release and static/dynamic"

  • При компилировании с /MD ссылка на "func" в источнике превращается в ссылку "__imp__func" в объекте, поскольку все время выполнения содержится в библиотеке DLL. При попытке компоновки со статической библиотекой LIBC.lib или LIBCMT.lib возникнет ошибка LNK2001 в __imp__func. При попытке компоновки с MSVCxx.lib при компилировании без /MD ошибка LNK2001 возникает не всегда, но высока вероятность возникновения других проблем.

  • Компоновка с библиотеками в режиме выпуска при построении отладочной версии приложения может вызвать ошибку LNK2001. Также использование параметра /Mxd (/MTd или /MDd) и/или определение _DEBUG с последующей компоновкой с выпущенными библиотеками повлечет за собой возможность возникновения неразрешенных внешних конфликтов (помимо прочих проблем). Компоновка построения в режиме выпуска с отладочными библиотеками также приведет к аналогичным проблемам.

  • Смешивание версий библиотек Microsoft или компиляторов может повлечь дополнительные трудности. Библиотеки новых версий компиляторов могут содержать новые символы, которые отсутствуют в библиотеках предыдущих версий. Вы можете захотеть изменить порядок директорий в путях поиска или изменить пути на соответствующие текущей версии.

    Диалоговое окно Инструменты | Параметры | Проекты | Директории VC++ в Выборе файлов библиотек позволяет изменить порядок поиска. Папка компоновщика в диалоговом окне параметров проекта также может содержать устаревшие пути.

    Такая проблема может возникнуть после установки нового SDK (возможно, в новое место), если порядок поиска не обновился с учетом нового расположения. Обычно необходимо указать путь к новому расположению директорий SDK напротив расположения Visual C++ по умолчанию. Также проект, содержащий встроенные пути, может по-прежнему указывать на старые пути, которые остались действующими, но являются устаревшими для новых функций, встроенных новой версией, установленной в другом месте.

  • В настоящее время не существует общего стандарта присвоения имен в C++ между поставщиками компиляторов и даже между различными версиями одного компилятора. Таким образом, компоновка объектных файлов с помощью других компиляторов может привести к несоблюдению схемы присвоения имен и, следовательно, вызвать ошибку LNK2001.

  • Смешивание внутренних и внешних параметров компилирования в различных модулях может вызвать ошибку LNK2001. Если библиотека C++ создана с включенной подстановкой функций (/Ob1 или /Ob2), а в соответствующем файле заголовка, описывающем функции, подстановка отключена (отсутствует ключевое слово inline), возникнет ошибка. Для предотвращения этого определите встроенные функции с помощью ключевого слова inline в файле заголовка, который вы планируете включить в остальные файлы.

  • Если вы используете директиву компилятора #pragma inline_depth, убедитесь, что значение равно 2 или более, а также убедитесь, что используется параметр компилирования /Ob1 или /Ob2.

  • Пропуск параметра /NOENTRY в LINK при создании ресурсной библиотеки DLL приведет к возникновению ошибки LNK2001.

  • Использование неверных параметров /SUBSYSTEM или /ENTRY способно вызвать ошибку LNK2001. Например, если вы пишете консольное приложение и указываете /SUBSYSTEM:WINDOWS, возникнет неразрешенный внешний конфликт с WinMain. Подробнее об этих параметрах и точках входа см. в параметрах компоновщика /SUBSYSTEM и /ENTRY.

Проблемы при экспорте

  • При переносе приложения с 16 разрядов на 32 или 64 может возникнуть ошибка LNK2001. Текущий синтаксис файла определения модуля (.DEF) требует, чтобы функции __cdecl, __stdcall и __fastcall были перечислены в разделе EXPORTS без подчеркиваний. Это отличается от 16-разрядного синтаксиса, где требуется подчеркивание. Подробнее см. в разделе EXPORTS файлов определения модулей.

  • Любой экспорт, указанный в DEF-файле и не найденный, вызовет ошибку LNK2001. Это может быть по причине того, что он не существует, неверно указан или использует внутреннее имя C++ (DEF-файлы не принимают внутренние имена).

Интерпретация вывода

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

На платформах x86 принято следующее соглашение о внутренних именах для имен, компилированных в C, или для внешних имен "C" в C++:

  • __cdecl
    Функции имеют в префиксе символ подчеркивания (_).

  • __stdcall
    Функции имеют в префиксе символ подчеркивания (_) и суффикс @, сопровождающийся двойным словом, обозначающим параметры в стеке.

  • __fastcall
    Функция имеет префикс @ и суффикс @ с последующим двойным словом, обозначающим параметры в стеке.

Используйте undname.exe для получения недекорированных имен из декорированных.

Подробнее о некоторых их перечисленных причин ошибки см. в разделе Декорирование имен.