Jak rozwiązać błąd LNK2019: nierozwiązany symbol zewnętrzny - funkcja?

101

Otrzymuję ten błąd, ale nie wiem, jak to naprawić.

Używam Visual Studio 2013. Nazwa rozwiązania została utworzona MyProjectTest Oto struktura mojego rozwiązania testowego:

Struktura

- 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;
}

Jestem początkujący; jest to prosty program, który działa bez błędów. Czytałem w internecie i zainteresowałem się testem jednostkowym, więc stworzyłem projekt testowy:

Plik> Nowy> Projekt ...> Zainstalowano> Szablony> Visual C ++> Test> Projekt testu jednostkowego natywnego>

Nazwa: UnitTest1 Rozwiązanie: Dodaj do rozwiązania Następnie lokalizacja zostanie automatycznie przełączona na ścieżkę aktualnie otwartego rozwiązania Oto struktura folderów rozwiązania:

Struktura folderów

Edytowałem tylko plik 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
        }

    };
}

Ale pojawia się błąd LNK2019: nierozwiązany symbol zewnętrzny. Wiem, że brakuje implementacji funkcji wielokrotnej . Próbowałem usunąć plik function.cpp i zastąpiłem deklarację definicją i uruchomiłem. Jednak zapisywanie zarówno deklaracji, jak i definicji w tym samym pliku nie jest zalecane. Jak mogę naprawić ten błąd bez robienia tego? Czy powinienem zastąpić #include "../MyProjectTest/function.cpp"w pliku unittest.cpp? (Nie jestem zbyt dobry z angielskiego. Dzięki)

phibao37
źródło
6
OSTROŻNOŚĆ W środowisku Windows biblioteki statyczne mają .LIBrozszerzenie pliku. Aby skomplikować sprawy ... Biblioteki *.DLLdołączane dynamicznie (tj. ) Mogą mieć towarzyszącą bibliotekę importu, która również ma .LIBrozszerzenie pliku. Ta biblioteka importu zawiera listę wszystkich gadżetów dostarczanych przez *.DLL. Aby uzyskać więcej informacji, przeczytaj: Przewodnik dla początkujących po
łącznikach
5
Dlaczego miałby uważać?
statek marszałkowy

Odpowiedzi:

82

Jedną z opcji byłoby to function.cppw swoim UnitTest1projekcie, ale to nie może być najbardziej struktura rozwiązanie idealne. Krótka odpowiedź na twój problem jest taka, że ​​podczas budowania UnitTest1projektu kompilator i konsolidator nie mają pojęcia, że function.cppistnieje, a także nie mają nic do połączenia, co zawiera definicję multiple. Sposobem na rozwiązanie tego problemu jest użycie łączenia bibliotek.

Ponieważ testy jednostkowe są w innym projekcie, zakładam, że Twoim zamiarem jest uczynienie tego projektu samodzielnym programem do testów jednostkowych. Dzięki funkcjom, które testujesz, znajdujących się w innym projekcie, możliwe jest zbudowanie tego projektu w bibliotece połączonej dynamicznie lub statycznie. Biblioteki statyczne są połączone z innymi programami w czasie kompilacji i mają rozszerzenie .lib, a biblioteki dynamiczne są połączone w czasie wykonywania i mają rozszerzenie .dll. Dla mojej odpowiedzi wolę biblioteki statyczne.

Możesz przekształcić swój pierwszy program w bibliotekę statyczną, zmieniając go we właściwościach projektu. Na karcie Ogólne powinna znajdować się opcja, w której projekt jest ustawiony na kompilację do pliku wykonywalnego ( .exe). Możesz to zmienić na .lib. .libPlik będzie budować w tym samym miejscu co .exe.

W swoim UnitTest1projekcie możesz przejść do jego właściwości i na karcie Linker w kategorii Dodatkowe katalogi biblioteczne dodać ścieżkę do której MyProjectTestkompilacje. Następnie, dla dodatkowych zależności na karcie Konsolidator - dane wejściowe, najprawdopodobniej dodaj nazwę biblioteki statycznej MyProjectTest.lib.

To powinno pozwolić na zbudowanie projektu. Zauważ, że robiąc to, MyProjectTestnie będzie samodzielnym programem wykonywalnym, chyba że zmienisz jego właściwości kompilacji w razie potrzeby, co byłoby mniej niż idealne.

kevintodisco
źródło
W „Linker-> Input Tab” musiałem przedrostek „(OutDir)” dla biblioteki statycznej, czyli „$ (OutDir) MyProjectTest.lib”, chociaż lokalizacja zarówno „MyProject”, jak i „MyTestProject” jest przechowywana w tym samym folderze głównym .
Pabitra Dash
15
Więc za każdym razem, gdy chcesz uruchomić testy jednostkowe, powinieneś przekonwertować projekt testera na bibliotekę statyczną, a za każdym razem, gdy chcesz uruchomić program, przekonwertuj go z powrotem na plik wykonywalny. Jak to jest rozwiązanie?
A. Smoliak
1
Jeśli MyProjectTest jest biblioteką dll, czy możemy to przetestować? Po prostu dodajemy import lib czy musimy dodać pliki obj?
aviit
„Możesz przekształcić swój pierwszy program w bibliotekę statyczną, zmieniając go we właściwościach projektu. Na karcie Ogólne powinna znajdować się opcja, w której projekt jest ustawiony na kompilację do pliku wykonywalnego (.exe). Możesz to zmienić na .lib Plik .lib zostanie skompilowany w tym samym miejscu, co plik .exe „W moim przypadku wystarczyło to. Resztę załatwił już VS.
Ekrem Solmaz
39

W drzewie rozwiązań programu Visual Studio kliknij prawym przyciskiem myszy projekt „UnitTest1”, a następnie Dodaj -> Istniejący element -> wybierz plik ../MyProjectTest/function.cpp

Niyaz Ivanov
źródło
4
Zwróć uwagę, że rzeczywiste pliki nie są kopiowane ani przenoszone do ProjDir.
Laurie Stearn
Ta metoda rozwiązała podobne problemy, które wystąpiły podczas próby dodania biblioteki c ++ do projektu CLI.
Deshan
17

Ponieważ chcę, aby mój projekt został skompilowany do samodzielnego EXE, połączyłem projekt UnitTest z plikiem function.obj wygenerowanym z pliku function.cpp i działa. Kliknij prawym przyciskiem myszy projekt „UnitTest1”> Właściwości konfiguracji> Konsolidator> Dane wejściowe> Dodatkowe zależności> dodaj „.. \ MyProjectTest \ Debug \ function.obj”

harrygg
źródło
1
A co z przypadkiem, gdy MyProjectTest jest biblioteką dll? Możesz to ustawić?
lot
Jeśli mamy wiele plików obj. czy możemy dodać coś takiego * .obj? Twoje rozwiązanie zadziałało ze mną, ale nie chcę ręcznie dodawać każdego nowego pliku obj.
aviit
10

Właśnie natknąłem się na ten problem w Visual Studio 2013. Najwyraźniej posiadanie dwóch projektów w tym samym rozwiązaniu i ustawienie zależności to za mało. Musisz dodać odniesienie do projektu między nimi. Aby to zrobić:

  1. Kliknij prawym przyciskiem myszy projekt w eksploracji rozwiązania
  2. Kliknij Dodaj => Referencje ...
  3. Kliknij przycisk Dodaj nowe odniesienie
  4. Zaznacz pola obok projektów, na których opiera się ten projekt
  5. Kliknij OK
Kevin Dill
źródło
Co masz na myśli, określając zależności? Dodałem odniesienie, ale nadal narzekałem. devblogs.microsoft.com/cppblog/cpp-testing-in-visual-studio zasugerował, że to wystarczy.
tschumann
8

okazało się, że używam plików .c z plikami .cpp. zmiana nazwy .c na .cpp rozwiązała mój problem.

cahit beyaz
źródło
6

Innym sposobem na uzyskanie tego błędu konsolidatora (tak jak ja) jest to, że eksportujesz wystąpienie klasy z biblioteki dll, ale nie zadeklarowałeś tej klasy jako importu / eksportu.

 #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

Tak więc, mimo że głównie eksportowałem tylko wystąpienie klasy Book book, o której Bookmowa powyżej, musiałem zadeklarować tę klasę jako klasę eksportu / importu, a w przeciwnym razie wywołanie book.WordCount()drugiej biblioteki dll powodowało błąd łącza.

zar
źródło
3

Przydarzyło mi się to, więc pomyślałem, że mogę podzielić się moim rozwiązaniem, tak proste, jak to było:

Sprawdź zestaw znaków obu projektów w Właściwości konfiguracyjne -> Ogólne -> Zestaw znaków

Mój projekt UnitTest używał domyślnego zestawu znaków Multi-Byte, podczas gdy moje biblioteki były w formacie Unicode .
Moja funkcja używała TCHAR jako parametru. W rezultacie w mojej bibliotece TCHAR został przekształcony w WCHAR, ale był to znak * w moim UnitTest: symbole były inne, ponieważ parametry w rzeczywistości nie były takie same.

Enyx
źródło
Dzięki, to pomaga mi rozwiązać problem :)
Perry Qian-MSFT
1

Właśnie odkryłem, że LNK2019występuje to podczas kompilacji w programie Visual Studio 2015, jeśli zapomnisz podać definicję zadeklarowanej funkcji wewnątrz klasy.

Błąd linkera był wysoce tajemniczy, ale zawęziłem to, czego brakowało, czytając błąd i podałem definicję poza klasą, aby to wyjaśnić.

Bzdurny
źródło
Problem w niektórych przypadkach polega na tym, że nagłówki zawierające definicje klas są ładnie przywoływane / dołączane, ale odpowiadające im cpps mogą nie być udostępnione linkerowi. Najlepszym sposobem sprawdzenia jest przejrzenie zależności zewnętrznych projektu w Eksploratorze rozwiązań. Byłoby jednak korzystne, gdyby VS wydał ostrzeżenie o istnieniu / włączeniu pliku dotyczące błędu.
Laurie Stearn,
1

w moim przypadku ustaw plik cpp na „kompilator C / C ++” we właściwości -> ogólne rozwiązanie błędu LNK2019.

pivnothebearrrrrrrrr
źródło
0

Dla mnie działa, jeśli dodać w tej linii ryk .vcxprojw itemGrouppliku cpp, który jest podłączony do pliku nagłówka.

<ClCompile Include="file.cpp" />
Nejc Galof
źródło
0

W programie Visual Studio 2017, jeśli chcesz przetestować członków publicznych, po prostu umieść swój prawdziwy projekt i projekt testowy w tym samym rozwiązaniu i dodaj odwołanie do swojego prawdziwego projektu w projekcie testowym.

Aby uzyskać więcej informacji, zobacz Testy jednostkowe języka C ++ w programie Visual Studio w blogu MSDN. Możesz również sprawdzić Napisz testy jednostkowe dla C / C ++ w programie Visual Studio, a także Użyj struktury testów jednostkowych firmy Microsoft dla języka C ++ w programie Visual Studio , to drugie dotyczy sytuacji, gdy chcesz przetestować niepubliczne elementy członkowskie i musisz umieścić testy w tym samym projekcie jako twój prawdziwy kod.

Pamiętaj, że rzeczy, które chcesz przetestować, będą musiały zostać wyeksportowane przy użyciu __declspec(dllexport). Aby uzyskać więcej informacji, zobacz Eksportowanie z biblioteki DLL przy użyciu __declspec (dllexport) .

user276648
źródło