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.