Błąd narzędzi konsolidatora LNK2001

nierozwiązany symbol zewnętrzny "symbol"

Skompilowany kod tworzy odwołanie lub wywołanie symbolu. Symbol nie jest zdefiniowany w żadnych bibliotekach ani plikach obiektów przeszukanych przez konsolidator.

Po tym komunikacie o błędzie następuje błąd krytyczny LNK1120. Aby naprawić LNK1120 błędów, najpierw napraw wszystkie błędy LNK2001 i LNK2019.

Istnieje wiele sposobów uzyskiwania błędów LNK2001. Wszystkie z nich obejmują odwołanie do funkcji lub zmiennej, którą konsolidator nie może rozpoznać lub znaleźć definicji. Kompilator może określić, kiedy kod nie deklaruje symbolu, ale nie wtedy, gdy go nie definiuje . Dzieje się tak, ponieważ definicja może znajdować się w innym pliku źródłowym lub bibliotece. Jeśli kod odwołuje się do symbolu, ale nigdy nie jest zdefiniowany, konsolidator generuje błąd.

Co to jest nierozwiązany symbol zewnętrzny?

Symbol to wewnętrzna nazwa funkcji lub zmiennej globalnej. Jest to forma nazwy używanej lub zdefiniowanej w skompilowanym pliku obiektu lub bibliotece. Zmienna globalna jest definiowana w pliku obiektu, w którym jest przydzielany magazyn. Funkcja jest definiowana w pliku obiektu, w którym jest umieszczany skompilowany kod treści funkcji. Symbol zewnętrzny jest jednym z odwołań w jednym pliku obiektu, ale zdefiniowanym w innej bibliotece lub pliku obiektu. Wyeksportowany symbol to taki, który jest publicznie dostępny przez plik obiektu lub bibliotekę, która go definiuje.

Aby utworzyć aplikację lub bibliotekę DLL, każdy użyty symbol musi mieć definicję. Konsolidator musi rozpoznać lub znaleźć zgodną definicję dla każdego symbolu zewnętrznego, do których odwołuje się każdy plik obiektu. Konsolidator generuje błąd, gdy nie może rozpoznać symbolu zewnętrznego. Oznacza to, że konsolidator nie może odnaleźć zgodnej wyeksportowanej definicji symboli w żadnym z połączonych plików.

Ten błąd może wystąpić:

  • Gdy w projekcie brakuje odwołania do biblioteki (. LIB) lub obiekt (. Plik OBJ). Aby rozwiązać ten problem, dodaj odwołanie do wymaganej biblioteki lub pliku obiektu do projektu. Aby uzyskać więcej informacji, zobacz lib Files as linker input (Pliki lib jako dane wejściowe konsolidatora).

  • Gdy projekt zawiera odwołanie do biblioteki (. LIB) lub obiekt (. Plik OBJ), który z kolei wymaga symboli z innej biblioteki. Może się to zdarzyć, nawet jeśli nie wywołasz funkcji, które powodują zależność. Aby rozwiązać ten problem, dodaj odwołanie do innej biblioteki do projektu. Aby uzyskać więcej informacji, zobacz Understanding the classic model for linking: Taking symbols along for the ride(Opis klasycznego modelu łączenia: tworzenie symboli na potrzeby jazdy).

  • Jeśli używasz /NODEFAULTLIB lub /Zl opcji. Po określeniu tych opcji bibliotek, które zawierają wymagany kod, nie są połączone z projektem, chyba że zostały jawnie dołączone. Aby rozwiązać ten problem, jawnie dołącz wszystkie biblioteki używane w wierszu polecenia linku. Jeśli podczas korzystania z tych opcji jest wyświetlanych wiele brakujących nazw funkcji CRT lub Biblioteki Standardowej, jawnie dołącz biblioteki CRT i biblioteki DLL lub pliki biblioteki w linku.

  • Jeśli kompilujesz przy użyciu /clr opcji. Być może brakuje odwołania do .cctorelementu . Aby uzyskać więcej informacji na temat rozwiązywania tego problemu, zobacz Inicjowanie zestawów mieszanych.

  • Jeśli łączysz się z bibliotekami trybu wydania podczas kompilowania wersji debugowania aplikacji. Podobnie, jeśli używasz opcji /MTd lub /MDd lub zdefiniować_DEBUG, a następnie połączyć się z bibliotekami wydania, należy oczekiwać wielu potencjalnych nierozwiązanych elementów zewnętrznych, między innymi. Łączenie kompilacji w trybie wydania z bibliotekami debugowania powoduje również podobne problemy. Aby rozwiązać ten problem, upewnij się, że używasz bibliotek debugowania w kompilacjach debugowania i bibliotek detalicznych w kompilacjach detalicznych.

  • Jeśli kod odwołuje się do symbolu z jednej wersji biblioteki, ale łączysz inną wersję biblioteki. Ogólnie rzecz biorąc, nie można mieszać plików obiektów ani bibliotek utworzonych dla różnych wersji kompilatora. Biblioteki dostarczane w jednej wersji mogą zawierać symbole, których nie można znaleźć w bibliotekach dołączonych do innych wersji. Aby rozwiązać ten problem, skompiluj wszystkie pliki obiektów i biblioteki z tą samą wersją kompilatora przed połączeniem ich razem. Aby uzyskać więcej informacji, zobacz Zgodność binarna języka C++ między wersjami programu Visual Studio.

  • Jeśli ścieżki biblioteki są nieaktualne. Okno dialogowe Opcje narzędzi > Projekty >> katalogów VC++ w obszarze wyboru Pliki biblioteki umożliwia zmianę kolejności wyszukiwania biblioteki. Folder Konsolidator w oknie dialogowym Strony właściwości projektu może również zawierać ścieżki, które mogą być nieaktualne.

  • Po zainstalowaniu nowego zestawu Windows SDK (być może w innej lokalizacji). Kolejność wyszukiwania biblioteki musi zostać zaktualizowana, aby wskazywała nową lokalizację. Zwykle należy umieścić ścieżkę do nowego zestawu SDK dołączania i katalogów bibliotek przed domyślną lokalizacją języka Visual C++. Ponadto projekt zawierający osadzone ścieżki może nadal wskazywać stare ścieżki, które są prawidłowe, ale nieaktualne. Zaktualizuj ścieżki dla nowych funkcji dodanych przez nową wersję zainstalowaną w innej lokalizacji.

  • Jeśli tworzysz w wierszu polecenia i utworzysz własne zmienne środowiskowe. Sprawdź, czy ścieżki do narzędzi, bibliotek i plików nagłówkowych przechodzą do spójnej wersji. Aby uzyskać więcej informacji, zobacz Use the MSVC toolset from the command line (Używanie zestawu narzędzi MSVC z wiersza polecenia).

Problemy z kodowaniem

Ten błąd może być spowodowany przez:

  • Niezgodna wielkość liter w kodzie źródłowym lub pliku definicji modułu (.def). Jeśli na przykład nadasz zmiennej var1 nazwę w jednym pliku źródłowym języka C++ i spróbujesz uzyskać do niej dostęp w inny VAR1 sposób, ten błąd zostanie wygenerowany. Aby rozwiązać ten problem, użyj spójnych nazw pisowni i liter.

  • Projekt, który używa podkreślenia funkcji. Może wystąpić podczas definiowania funkcji jako inline w pliku źródłowym, a nie w pliku nagłówkowym. Wbudowane funkcje nie mogą być widoczne poza plikiem źródłowym, który je definiuje. Aby rozwiązać ten problem, zdefiniuj funkcje w nagłówkach, w których są deklarowane.

  • Wywoływanie funkcji C z programu C++ bez użycia extern "C" deklaracji dla funkcji C. Kompilator używa różnych wewnętrznych konwencji nazewnictwa symboli dla kodu C i C++. Nazwa symboli wewnętrznych jest tym, czego szuka konsolidator podczas rozpoznawania symboli. Aby rozwiązać ten problem, użyj extern "C" otoki wokół wszystkich deklaracji funkcji języka C używanych w kodzie języka C++, co powoduje, że kompilator używa wewnętrznej konwencji nazewnictwa języka C dla tych symboli. Opcje kompilatora /Tp i /Tc powodują, że kompilator skompiluje pliki odpowiednio jako C++ lub C, niezależnie od rozszerzenia nazwy pliku. Te opcje mogą spowodować, że nazwy funkcji wewnętrznych różnią się od oczekiwanych.

  • Próba odwołania się do funkcji lub danych, które nie mają powiązania zewnętrznego. W języku C++funkcje wbudowane i const dane mają wewnętrzne powiązania, chyba że jawnie określono jako extern. Aby rozwiązać ten problem, użyj jawnych extern deklaracji w symbolach, o których mowa poza definiującym plikiem źródłowym.

  • Brak treści funkcji lub definicji zmiennej. Ten błąd jest typowy podczas deklarowania, ale nie definiuje się zmiennych, funkcji ani klas w kodzie. Kompilator potrzebuje tylko prototypu funkcji lub extern deklaracji zmiennej, aby wygenerować plik obiektu bez błędu, ale konsolidator nie może rozpoznać wywołania funkcji ani odwołania do zmiennej, ponieważ nie ma kodu funkcji ani przestrzeni zmiennej zarezerwowanej. Aby rozwiązać ten problem, upewnij się, że wszystkie przywoływały funkcje i zmienne w pliku źródłowym lub bibliotece, którą łączysz.

  • Wywołanie funkcji, które używa typów zwracanych i parametrów lub konwencji wywoływania, które nie są zgodne z tymi w definicji funkcji. W plikach obiektów języka C++ dekoracja nazw koduje konwencję wywoływania, zakres klas lub przestrzeni nazw oraz zwraca i typy parametrów funkcji. Zakodowany ciąg staje się częścią ostatecznej nazwy funkcji ozdobionej. Ta nazwa jest używana przez konsolidator do rozpoznawania lub dopasowywania wywołań funkcji z innych plików obiektów. Aby rozwiązać ten problem, upewnij się, że deklaracja, definicja i wywołania funkcji używają tych samych zakresów, typów i konwencji wywoływania.

  • Wywoływany kod języka C++ w przypadku uwzględnienia prototypu funkcji w definicji klasy, ale nie obejmuje implementacji funkcji. Aby rozwiązać ten problem, należy podać definicję wszystkich wywoływanych składowych klasy.

  • Próba wywołania czystej funkcji wirtualnej z abstrakcyjnej klasy bazowej. Czysta funkcja wirtualna nie ma implementacji klasy bazowej. Aby rozwiązać ten problem, upewnij się, że zaimplementowano wszystkie nazywane funkcjami wirtualnymi.

  • Próba użycia zmiennej zadeklarowanej w funkcji (zmiennej lokalnej) poza zakresem tej funkcji. Aby rozwiązać ten problem, usuń odwołanie do zmiennej, która nie znajduje się w zakresie, lub przenieś zmienną do wyższego zakresu.

  • Podczas kompilowania wersji projektu ATL w celu utworzenia komunikatu wymaganego jest kod startowy CRT. Aby rozwiązać ten problem, wykonaj jedną z następujących czynności:

    • Usuń _ATL_MIN_CRT z listy preprocesor definiuje, aby umożliwić dołączanie kodu startowego CRT. Aby uzyskać więcej informacji, zobacz Stronę właściwości ogólne (Project).

    • Jeśli to możliwe, usuń wywołania funkcji CRT, które wymagają kodu uruchamiania CRT. Zamiast tego należy użyć ich odpowiedników Win32. Na przykład użyj polecenia lstrcmp zamiast strcmp. Znane funkcje, które wymagają kodu uruchamiania CRT, to niektóre funkcje ciągu i zmiennoprzecinkowe.

Problemy ze spójnością

Obecnie nie ma standardu dla dekoracji nazw języka C++ między dostawcami kompilatora, a nawet między różnymi wersjami tego samego kompilatora. Pliki obiektów skompilowane z różnymi kompilatorami mogą nie używać tego samego schematu nazewnictwa. Łączenie ich może spowodować błąd LNK2001.

Mieszanie wbudowanych i nieliniowych opcji kompilacji w różnych modułach może spowodować LNK2001. Jeśli biblioteka języka C++ jest tworzona z włączonym tworzeniem funkcji (/Ob1 lub /Ob2), ale odpowiedni plik nagłówkowy opisujący funkcje jest wyłączony (bez inline słowa kluczowego), ten błąd występuje. Aby rozwiązać ten problem, zdefiniuj funkcje inline w pliku nagłówkowym, który należy uwzględnić w innych plikach źródłowych.

Jeśli używasz #pragma inline_depth dyrektywy kompilatora, upewnij się, że ustawiono wartość 2 lub większą i upewnij się, że używasz również opcji kompilatora /Ob1 lub /Ob2 .

Ten błąd może wystąpić, jeśli pominięto opcję LINK /NOENTRY podczas tworzenia biblioteki DLL tylko dla zasobów. Aby rozwiązać ten problem, dodaj /NOENTRY opcji do polecenia linku.

Ten błąd może wystąpić, jeśli w projekcie użyto nieprawidłowych ustawień /SUBSYSTEM lub /ENTRY. Jeśli na przykład napiszesz aplikację konsolową i określisz /SUBSYSTEM:WINDOWS, dla elementu WinMainzostanie wygenerowany nierozwiązany błąd zewnętrzny . Aby rozwiązać ten problem, upewnij się, że opcje są zgodne z typem projektu. Aby uzyskać więcej informacji na temat tych opcji i punktów wejścia, zobacz /PODSYSTEM i /ENTRY opcje konsolidatora.

Problemy z wyeksportowanym symbolem pliku def

Ten błąd występuje, gdy nie można odnaleźć eksportu wymienionego w pliku def. Może to być spowodowane tym, że eksport nie istnieje, jest niepoprawnie wpisana lub używa nazw ozdobionych języka C++. Plik .def nie bierze nazw ozdobionych. Aby rozwiązać ten problem, usuń niepotrzebne eksporty i użyj extern "C" deklaracji dla eksportowanych symboli.

Użyj nazwy ozdobionej, aby znaleźć błąd

Kompilator języka C++ i konsolidator używają funkcji Name Decoration, znanej również jako name-mangling. Dekoracja nazw koduje dodatkowe informacje o typie zmiennej w nazwie symbolu. Nazwa symbolu funkcji koduje zwracany typ, typy parametrów, zakres i konwencję wywoływania. Ta nazwa ozdobiona jest nazwą symbolu wyszukiwaną przez konsolidatora w celu rozpoznania symboli zewnętrznych.

Błąd łącza może spowodować, że deklaracja funkcji lub zmiennej nie jest dokładnie zgodna z definicją funkcji lub zmiennej. Dzieje się tak, ponieważ każda różnica staje się częścią nazwy symbolu, która ma być zgodna. Błąd może wystąpić, nawet jeśli ten sam plik nagłówka jest używany zarówno w kodzie wywołującym, jak i w kodzie definiującym. Jednym ze sposobów może być skompilowanie plików źródłowych przy użyciu różnych flag kompilatora. Jeśli na przykład kod jest kompilowany w celu używania __vectorcall konwencji wywoływania, ale łączysz się z biblioteką, która oczekuje, że klienci będą wywoływać go przy użyciu konwencji domyślnej __cdecl lub __fastcall wywołującej. W takim przypadku symbole nie są zgodne, ponieważ konwencje wywoływania są różne.

Aby ułatwić znalezienie przyczyny, komunikat o błędzie zawiera dwie wersje nazwy. Wyświetla zarówno "przyjazną nazwę", nazwę używaną w kodzie źródłowym, jak i nazwę ozdobioną (w nawiasach). Nie musisz wiedzieć, jak interpretować nazwę ozdobioną. Nadal można wyszukiwać i porównywać je z innymi nazwami ozdobionymi. Narzędzia wiersza polecenia mogą pomóc znaleźć i porównać oczekiwaną nazwę symbolu oraz rzeczywistą nazwę symbolu:

  • Opcje /EXPORT i /SYMBOLS narzędzia wiersza polecenia DUMPBIN są przydatne tutaj. Mogą one pomóc w odnalezieniu symboli zdefiniowanych w plikach dll i obiektów lub bibliotek. Możesz użyć listy symboli, aby sprawdzić, czy wyeksportowane nazwy ozdobione pasują do nazw ozdobionych wyszukiwanych przez konsolidatora.

  • W niektórych przypadkach konsolidator może zgłosić tylko nazwę ozdobioną symbolu. Możesz użyć narzędzia wiersza polecenia UNDNAME, aby uzyskać nieukodowaną formę nazwy ozdobionej.

Dodatkowe zasoby

Aby uzyskać więcej informacji, zobacz pytanie Stack Overflow "Co to jest niezdefiniowane odwołanie/nierozwiązany błąd symbolu zewnętrznego i jak go naprawić?".