Erro das Ferramentas de Vinculador LNK2001

símbolo externo não resolvido "símbolo"

O código compilado faz uma referência ou chamada ao símbolo. O símbolo não está definido nas bibliotecas ou nos arquivos de objeto pesquisados pelo vinculador.

Esta mensagem de erro é seguida do erro fatal LNK1120. Para corrigir o erro LNK1120, primeiro corrija todos os erros LNK2001 e LNK2019.

Há muitas maneiras de receber erros LNK2001. Todas elas envolvem uma referência a uma função ou variável que o vinculador não pode resolver ou para a qual ele não pode encontrar uma definição. O compilador pode identificar quando o código não declara um símbolo, mas não quando ele não define um. Isso ocorre porque a definição pode estar em um arquivo ou uma biblioteca de origem diferente. Se o código se referir a um símbolo, mas nunca for definido, o vinculador gerará um erro.

O que é um símbolo externo não resolvido?

Um símbolo é o nome interno de uma função ou variável global. É a forma do nome usada ou definida em uma biblioteca ou um arquivo de objeto compilado. Uma variável global é definida no arquivo de objeto em que o armazenamento é alocado para ela. Uma função é definida no arquivo de objeto em que é colocado o código compilado para o corpo da função. Um símbolo externo é referenciado em um arquivo de objeto, mas definido em um arquivo de objeto ou biblioteca diferente. Um símbolo exportado é disponibilizado publicamente pelo arquivo de objeto ou pela biblioteca que o define.

Para criar um aplicativo ou DLL, cada símbolo usado deve ter uma definição. O vinculador deve resolver ou encontrar a definição correspondente para cada símbolo externo referenciado por cada arquivo de objeto. O vinculador gera um erro, quando não consegue resolver um símbolo externo. Isso significa que o vinculador não conseguiu encontrar uma definição de símbolo exportado correspondente em nenhum dos arquivos vinculados.

Esse erro pode ocorrer:

  • Quando o projeto não tem uma referência a um arquivo de biblioteca (.LIB) ou de objeto (.OBJ). Para corrigir esse problema, adicione uma referência ao arquivo de biblioteca ou de objeto necessário para o projeto. Para obter mais informações, confira Arquivos de biblioteca como entrada de vinculador.

  • Quando o projeto tem uma referência a um arquivo de biblioteca (.LIB) ou de objeto (.OBJ) que, por sua vez, requer símbolos de outra biblioteca. Isso pode acontecer mesmo se você não chamar funções que causam a dependência. Para corrigir esse problema, adicione uma referência à outra biblioteca para o projeto. Para obter mais informações, confira Noções básicas sobre o modelo clássico para vinculação: como incluir os símbolos.

  • Se você usar as opções /NODEFAULTLIB ou /Zl. Quando você especifica essas opções, as bibliotecas que contêm o código necessário não são vinculadas ao projeto, a menos que você as tenha incluído explicitamente. Para corrigir esse problema, inclua explicitamente todas as bibliotecas que você usa na linha de comando do link. Se você observar que há muitos nomes de função Biblioteca Standard ou CRT ausentes ao usar essas opções, inclua explicitamente as DLLs de Biblioteca Standard e CRT ou arquivos de biblioteca no link.

  • Se você compilar usando a opção /clr. Pode haver uma referência ausente para .cctor. Para obter mais informações sobre como corrigir esse problema, confira Inicialização de assemblies misturados.

  • Se você vincular às bibliotecas do modo de lançamento ao criar uma versão de depuração de um aplicativo. Da mesma forma, se você usar as opções /MTd ou /MDd ou definir _DEBUG e vincular às bibliotecas de lançamento, deve esperar muitos possíveis externos não resolvidos, entre outros problemas. Vincular um build no modo de lançamento com as bibliotecas de depuração também causa problemas semelhantes. Para corrigir esse problema, use as bibliotecas de depuração nos builds de depuração e bibliotecas de varejo nos builds de varejo.

  • Se o código se referir a um símbolo de uma versão de biblioteca, mas você vincular uma versão diferente da biblioteca. Geralmente, você não pode misturar arquivos de objeto ou bibliotecas criados para versões diferentes do compilador. As bibliotecas enviadas em uma versão podem conter símbolos que não podem ser encontrados nas bibliotecas incluídas com outras versões. Para corrigir esse problema, crie todos os arquivos de objeto e bibliotecas com a mesma versão do compilador, antes de vinculá-los juntos. Para obter mais informações, consulte Compatibilidade binária do C++ entre versões do Visual Studio.

  • Se os caminhos de biblioteca estiverem desatualizados. A caixa de diálogo Ferramentas > Opções > Projetos > Diretórios do VC++, na seleção Arquivos de biblioteca, permite alterar a ordem de pesquisa da biblioteca. A pasta Vinculador na caixa de diálogo Páginas de Propriedades do projeto também pode conter caminhos que podem estar desatualizados.

  • Quando um novo SDK do Windows é instalado (talvez em um local diferente). A ordem de pesquisa da biblioteca deve ser atualizada para apontar para o novo local. Normalmente, você deve colocar o caminho para os novos diretórios de inclusão e biblioteca do SDK na frente do local padrão do Visual C++. Além disso, um projeto que contém caminhos inseridos ainda pode apontar para caminhos antigos válidos, mas desatualizados. Atualize os caminhos para as novas funcionalidades adicionadas pela nova versão instalada em um local diferente.

  • Se você criar na linha de comando e tiver criado suas próprias variáveis de ambiente. Verifique se os caminhos para as ferramentas, as bibliotecas e os arquivos de cabeçalho acessam uma versão consistente. Para obter mais informações, confira Usar o conjunto de ferramentas do MSVC na linha de comando.

Problemas de codificação

Esse erro pode ser causado por:

  • Caso incompatível no código-fonte ou no arquivo de definição de módulo (.def). Por exemplo, se você nomear uma variável var1 em um arquivo de origem do C++ e tentar acessá-la como VAR1 em outro, esse erro será gerado. Para corrigir esse problema, use nomes com ortografia e uso de maiúsculas consistentes.

  • Um projeto que usa inlining de função. Isso pode ocorrer quando você define as funções como inline em um arquivo de origem, em vez de fazê-lo em um arquivo de cabeçalho. Não é possível ver as funções embutidas fora do arquivo de origem que as define. Para corrigir esse problema, defina as funções embutidas nos cabeçalhos em que elas são declaradas.

  • Chamar uma função do C de um programa do C++, sem usar uma declaração extern "C" para a função do C. O compilador usa diferentes convenções de nomenclatura de símbolos internos para código C e C++. O vinculador procura o nome do símbolo interno ao resolver símbolos. Para corrigir esse problema, use um wrapper extern "C" em todas as declarações das funções do C usadas no código C++, o que faz com que o compilador use a convenção de nomenclatura interna do C para esses símbolos. As opções do compilador /Tp e /Tc fazem com que o compilador compile arquivos como C++ ou C, respectivamente, a despeito de qual seja a extensão de nome de arquivo. Essas opções podem fazer com que os nomes de funções internas sejam diferentes do esperado.

  • Uma tentativa de referenciar funções ou dados que não têm vinculação externa. No C++, as funções embutidas e os dados const têm vinculação interna, a menos que especificados explicitamente como extern. Para corrigir esse problema, use as declarações explícitas extern nos símbolos referidos fora da definição do arquivo de origem.

  • Uma definição de corpo de função ou variável ausente. Esse erro é comum quando você declara, mas não define as variáveis, funções ou classes no código. O compilador só precisa de um protótipo de função ou declaração de variável extern para gerar um arquivo de objeto sem erro, mas o vinculador não pode resolver uma chamada para a função ou uma referência à variável, pois não há código de função ou espaço de variável reservado. Para corrigir esse problema, defina cada função e variável referenciada em uma biblioteca ou arquivo de origem vinculado.

  • Uma chamada de função que usa tipos de retorno e parâmetros ou convenções de chamada que não correspondem às da definição de função. Nos arquivos de objeto C++, a Decoração de nome codifica a convenção de chamada, a classe ou o escopo de namespace e os tipos de retorno e de parâmetro de uma função. A cadeia de caracteres codificada torna-se parte do nome final da função decorada. Esse nome é usado pelo vinculador para resolver ou corresponder as chamadas para a função de outros arquivos de objeto. Para corrigir esse problema, verifique se a declaração de função, a definição e as chamadas usam os mesmos escopos, tipos e convenções de chamada.

  • O código C++ que você chama quando inclui um protótipo de função em uma definição de classe, mas não inclui a implementação da função. Para corrigir esse problema, forneça uma definição para todos os membros da classe que você chamar.

  • Uma tentativa de chamar uma função virtual pura de uma classe base abstrata. Uma função virtual pura não tem implementação de classe base. Para corrigir esse problema, verifique se todas as funções virtuais chamadas foram implementadas.

  • Tentativa de usar uma variável declarada em uma função (uma variável local) fora do escopo dessa função. Para corrigir esse problema, remova a referência à variável que não está no escopo ou mova a variável para um escopo maior.

  • Quando você cria uma versão de Lançamento de um projeto ATL, produzindo uma mensagem de que o código de inicialização CRT é necessário. Para corrigir esse problema, adote uma das seguintes medidas:

    • Remova _ATL_MIN_CRT da lista de pré-processadores definidos para permitir que o código de inicialização CRT seja incluído. Para obter mais informações, confira Página de propriedades gerais (projeto).

    • Se possível, remova as chamadas às funções CRT que exigem o código de inicialização CRT. Em vez disso, use os equivalentes do Win32. Por exemplo, use lstrcmp ao invés de strcmp. As funções conhecidas que exigem o código de inicialização CRT são algumas das funções de cadeia de caracteres e de ponto flutuante.

Problemas de consistência

No momento, não há padrão para decoração de nome do C++ entre fornecedores de compilador ou até mesmo entre versões diferentes do mesmo compilador. Os arquivos de objeto compilados com compiladores diferentes podem não usar o mesmo esquema de nomenclatura. Vinculá-los pode causar o erro LNK2001.

Misturar opções de compilação embutidas e não embutidas em módulos diferentes pode causar o LNK2001. Se uma biblioteca do C++ for criada com o inlining de função ativado (/Ob1 ou /Ob2), mas o arquivo de cabeçalho correspondente que descreve as funções tiver o inlining desativado (sem a palavra-chave inline), esse erro ocorrerá. Para corrigir esse problema, defina as funções inline no arquivo de cabeçalho que você incluir em outros arquivos de origem.

Se você usar a diretiva do compilador #pragma inline_depth, defina um valor de 2 ou maior e use também a opção do compilador /Ob1 ou /Ob2.

Esse erro pode ocorrer se você omitir a opção de LINK /NOENTRY ao criar uma DLL somente recurso. Para corrigir esse problema, adicione a opção /NOENTRY ao comando de link.

Esse erro pode ocorrer se você usar as configurações incorretas de /SUBSYSTEM ou /ENTRY no projeto. Por exemplo, se você escrever um aplicativo de console e especificar /SUBSYSTEM:WINDOWS, um erro externo não resolvido será gerado para WinMain. Para corrigir esse problema, verifique se você corresponde às opções com o tipo de projeto. Para obter mais informações sobre essas opções e pontos de entrada, confira as opções de vinculador /SUBSYSTEM e /ENTRY.

Problemas de símbolo de arquivo .def exportado

Esse erro ocorre quando uma exportação listada em um arquivo .def não é encontrada. Isso pode ocorrer porque a exportação não existe, está escrita incorretamente ou usa nomes decorados do C++. Um arquivo .def não usa nomes decorados. Para corrigir esse problema, remova as exportações desnecessárias e use declarações extern "C" para símbolos exportados.

Usar o nome decorado para localizar o erro

O compilador e o vinculador do C++ usam a Decoração de Nome, também conhecida como name-mangling. A decoração de nome codifica as informações adicionais sobre o tipo de uma variável no nome do símbolo. O nome do símbolo de uma função codifica o tipo de retorno, os tipos de parâmetro, o escopo e a convenção de chamada. Esse nome decorado é o nome do símbolo que o vinculador procura para resolver os símbolos externos.

Pode ocorrer um erro de link, se a declaração de uma função ou variável não corresponder exatamente à definição da função ou variável. Isso ocorre porque qualquer diferença se torna parte do nome do símbolo a ser correspondido. O erro pode ocorrer ainda que o mesmo arquivo de cabeçalho seja usado no código de chamada e no código de definição. Uma maneira em que isso pode ocorrer é se você compilar os arquivos de origem usando diferentes sinalizadores do compilador. Por exemplo, se o código for compilado para usar a convenção de chamada __vectorcall, mas você vincular a uma biblioteca que espera que os clientes o chamem usando a convenção de chamada __cdecl ou __fastcall padrão. Nesse caso, os símbolos não corresponderão porque as convenções de chamada são diferentes.

Para ajudar a encontrar a causa, a mensagem de erro mostra duas versões do nome. Ela exibe o "nome amigável", o nome usado no código-fonte e o nome decorado (entre parênteses). Você não precisa saber como interpretar o nome decorado. Você ainda pode pesquisar e compará-lo com outros nomes decorados. As ferramentas de linha de comando podem ajudar a localizar e comparar o nome do símbolo esperado e o nome real do símbolo:

  • As opções /EXPORTS e /SYMBOLS da ferramenta de linha de comando DUMPBIN são úteis aqui. Elas podem ajudar a descobrir quais símbolos são definidos no .dll e nos arquivos de objeto ou de biblioteca. Você pode usar a lista de símbolos para verificar se os nomes decorados exportados correspondem aos nomes decorados que o vinculador procura.

  • Em alguns casos, o vinculador só pode relatar o nome decorado de um símbolo. Você pode usar a ferramenta de linha de comando UNDNAME para obter a forma não decorada de um nome decorado.

Recursos adicionais

Para obter mais informações, confira a pergunta do Stack Overflow "O que é um erro de símbolo externo não resolvido/referência indefinida e como corrigi-lo?".