Como resolver o erro LNK2019: símbolo externo não resolvido - função?


99

Recebo este erro, mas não sei como corrigi-lo.

Estou usando o Visual Studio 2013. Fiz o nome da solução MyProjectTest Esta é a estrutura da minha solução de teste:

A estrutura

- function.h

#ifndef MY_FUNCTION_H
#define MY_FUNCTION_H

int multiple(int x, int y);
#endif

-function.cpp

#include "function.h"

int multiple(int x, int y){
    return x*y;
}

- main.cpp

#include <iostream>
#include <cstdlib>
#include "function.h"
using namespace std;

int main(){
    int a, b;
    cin >> a >> b;
    cout << multiple(a, b) << endl;

    system("pause");
    return 0;
}

Eu sou um iniciante; este é um programa simples e funciona sem erros. Li na internet e me interessei pelo teste unitário, então criei um projeto de teste:

Arquivo> Novo> Projeto ...> Instalado> Modelos> Visual C ++> Teste> Projeto de Teste de Unidade Nativa>

Nome: UnitTest1 Solução: Adicionar à solução Em seguida, o local mudou automaticamente para o caminho da solução aberta atual Esta é a estrutura de pastas da solução:

Estrutura da pasta

Eu só editei o arquivo unittest1.cpp:

#include "stdafx.h"
#include "CppUnitTest.h"
#include "../MyProjectTest/function.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace UnitTest1
{       
    TEST_CLASS(UnitTest1)
    {
    public:

        TEST_METHOD(TestEqual)
        {

            Assert::AreEqual(multiple(2, 3), 6);
            // TODO: Your test code here
        }

    };
}

Mas recebo o erro LNK2019: símbolo externo não resolvido. Eu sei que a implementação da função múltipla está faltando. Tentei excluir o arquivo function.cpp, substituí a declaração pela definição e ele foi executado. Mas escrever a declaração e a definição no mesmo arquivo não é recomendado. Como posso corrigir esse erro sem fazer isso? Devo substituir por #include "../MyProjectTest/function.cpp"no arquivo unittest.cpp? (Não sou muito bom em inglês. Obrigado)



6
TOME CUIDADO Em um ambiente Windows , as bibliotecas estáticas têm uma .LIBextensão de arquivo. Para complicar as coisas ... as bibliotecas de vínculo dinâmico (isto é *.DLL) podem ter uma biblioteca de importação que também tem uma .LIBextensão de arquivo. Esta biblioteca de importação lista todos os recursos fornecidos pelo *.DLL. Para obter mais informações, leia: Guia do Iniciante para
— Linkers

4
Por que ele deveria ter cuidado ??
— Marechal Craft

Respostas:


80

Uma opção seria incluir function.cppem seu UnitTest1projeto, mas essa pode não ser a estrutura de solução mais ideal. A resposta curta para o seu problema é que, ao construir seu UnitTest1projeto, o compilador e o vinculador não têm ideia da sua existência function.cppe também não têm nada para vincular que contenha uma definição multiple. Uma maneira de corrigir isso é usar bibliotecas de links.

Como seus testes de unidade estão em um projeto diferente, estou assumindo que sua intenção é fazer desse projeto um programa de teste de unidade autônomo. Com as funções que você está testando localizadas em outro projeto, é possível construir esse projeto para uma biblioteca vinculada dinâmica ou estaticamente. Bibliotecas estáticas são vinculadas a outros programas em tempo de construção e têm a extensão .lib, e bibliotecas dinâmicas são vinculadas em tempo de execução e têm a extensão .dll. Para minha resposta, prefiro bibliotecas estáticas.

Você pode transformar seu primeiro programa em uma biblioteca estática, alterando-o nas propriedades do projeto. Deve haver uma opção na guia Geral, onde o projeto é definido para ser compilado em um executável ( .exe). Você pode alterar isso para .lib. O .libarquivo será compilado no mesmo lugar que o .exe.

Em seu UnitTest1projeto, você pode acessar suas propriedades e, na guia Linker na categoria Diretórios de biblioteca adicionais, adicionar o caminho para o qual MyProjectTestcompila. Em seguida, para Dependências adicionais na guia Vinculador - Entrada, provavelmente adicione o nome de sua biblioteca estática MyProjectTest.lib.

Isso deve permitir que seu projeto seja construído. Observe que, ao fazer isso, MyProjectTestnão será um programa executável autônomo a menos que você altere suas propriedades de construção conforme necessário, o que seria menos do que o ideal.


Em 'Linker-> Input Tab', eu tive que prefixar '(OutDir)' para a biblioteca estática, que é '$ (OutDir) MyProjectTest.lib', embora a localização de 'MyProject' e 'MyTestProject' fosse mantida na mesma pasta raiz .
— Pabitra Dash

13
Portanto, toda vez que você deseja executar testes de unidade, deve converter seu projeto de testado em uma biblioteca estática, e toda vez que você realmente deseja executar seu programa, você o converte de volta em um executável, como isso é uma solução?
— A. Smoliak 01 de

1
Se MyProjectTest for uma dll, podemos testá-lo? Nós apenas adicionamos a lib de importação ou devemos adicionar os arquivos obj?
— aviit

"Você pode transformar seu primeiro programa em uma biblioteca estática alterando-o nas propriedades do projeto. Deve haver uma opção na guia Geral, onde o projeto está definido para ser compilado em um executável (.exe). Você pode alterar para .lib . O arquivo .lib será compilado no mesmo lugar que o .exe "Fazer isso foi o suficiente para o meu caso. O resto já foi tratado pela VS.
— Ekrem Solmaz

39

Na árvore de soluções do Visual Studio, clique com o botão direito do mouse no projeto 'UnitTest1' e em Adicionar -> Item existente -> escolha o arquivo ../MyProjectTest/function.cpp


4
Observe que os arquivos reais não são copiados ou movidos para o ProjDir.
— Laurie Stearn

Este método resolveu problemas semelhantes que ocorriam ao tentar adicionar c ++ lib a um projeto CLI.
— Deshan

17

Como desejo que meu projeto seja compilado em um EXE autônomo, vinculei o projeto UnitTest ao arquivo function.obj gerado a partir de function.cpp e ele funcionou. Clique com o botão direito no projeto 'UnitTest1'> Propriedades de configuração> Linker> Input> Additional Dependencies> add ".. \ MyProjectTest \ Debug \ function.obj"


1
Que tal o caso em que MyProjectTest é uma dll? Você pode definir para isso?
— aviit

Se tivermos muitos arquivos obj. podemos adicionar algo como este * .obj? Sua solução funcionou comigo, mas não quero adicionar manualmente todos os novos arquivos obj.
— aviit

10

Acabei de ter esse problema no Visual Studio 2013. Aparentemente agora, ter dois projetos na mesma solução e definir as dependências não é suficiente. Você precisa adicionar uma referência de projeto entre eles. Fazer isso:

  1. Clique com o botão direito no projeto para explorar a solução
  2. Clique em Adicionar => Referências ...
  3. Clique no botão Adicionar Nova Referência
  4. Marque as caixas dos projetos dos quais este projeto depende
  5. Clique OK

O que você quer dizer com definir as dependências? Eu adicionei a referência, mas ele ainda reclamava. devblogs.microsoft.com/cppblog/cpp-testing-in-visual-studio sugeriu que seria o suficiente.
— tschumann

8

descobri que eu estava usando arquivos .c com arquivos .cpp. renomear .c para .cpp resolveu meu problema.


6

Outra maneira de obter esse erro de vinculador (como eu) é se você estiver exportando uma instância de uma classe de uma dll, mas não tiver declarado essa classe como importação / exportação.

 #ifdef  MYDLL_EXPORTS 
    #define DLLEXPORT __declspec(dllexport)  
 #else
    #define DLLEXPORT __declspec(dllimport)  
 #endif

class DLLEXPORT Book // <--- this class must also be declared as export/import
{
public: 
    Book();
    ~Book();
    int WordCount();
};

DLLEXPORT extern Book book; // <-- This is what I really wanted, to export book object

Portanto, embora eu estivesse exportando principalmente apenas uma instância da classe Book chamada bookacima, tive que declarar a Bookclasse como classe de exportação / importação, caso contrário, chamar book.WordCount()a outra dll estava causando um erro de link.


2

Isso aconteceu comigo, então pensei que poderia compartilhar minha solução, por mais simples que fosse:

Verifique o conjunto de caracteres de ambos os projetos em Propriedades de configuração -> Geral -> Conjunto de caracteres

Meu projeto UnitTest estava usando o padrão Character Set Multi-Byte enquanto meus libs onde em Unicode .
Minha função estava usando um TCHAR como parâmetro. Como resultado, em minha lib, meu TCHAR foi transformado em um WCHAR, mas era um char * em meu UnitTest: o símbolo era diferente porque os parâmetros não eram realmente os mesmos no final.


1

Acabei de descobrir que LNK2019ocorre durante a compilação no Visual Studio 2015, se esquecendo de fornecer uma definição para uma função declarada dentro de uma classe.

O erro do linker era altamente enigmático, mas reduzi o que estava faltando lendo o erro e forneci a definição fora da classe para esclarecer isso.


O problema em alguns casos é que os cabeçalhos contendo a classe defs são todos bem referenciados / incluídos, mas seus cpps correspondentes podem não ser disponibilizados para o vinculador. A melhor maneira de verificar é percorrer as dependências externas do projeto no Solution Explorer. Seria benéfico para o VS emitir algum tipo de aviso de existência / inclusão de arquivo em relação ao erro.
— Laurie Stearn

1

no meu caso, defina o arquivo cpp para "compilador C / C ++" na propriedade -> geral resolver o erro LNK2019.


0

Para mim funciona, se eu adicionar esta abaixo linha .vcxprojno itemGrouparquivo CPP, que está ligado ao arquivo de cabeçalho.

<ClCompile Include="file.cpp" />

0

No Visual Studio 2017, se você deseja testar membros públicos, simplesmente coloque seu projeto real e projeto de teste na mesma solução e adicione uma referência ao seu projeto real no projeto de teste.

Consulte Teste de unidade C ++ no Visual Studio no blog do MSDN para obter mais detalhes. Você também pode marcar Gravar testes de unidade para C / C ++ no Visual Studio , bem como Usar o Microsoft Unit Testing Framework para C ++ no Visual Studio , sendo o último caso você precise testar membros não públicos e colocar os testes no mesmo projeto como seu código real.

Observe que o que você deseja testar precisará ser exportado usando __declspec(dllexport). Consulte Exportando de uma DLL usando __declspec (dllexport) para obter mais detalhes.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.