Bagikan melalui


LNK2001 Kesalahan Alat Linker

simbol eksternal "simbol" yang tidak terselesaikan

Kode yang dikompilasi membuat referensi atau panggilan ke simbol. Simbol tidak ditentukan dalam pustaka atau file objek apa pun yang dicari oleh linker.

Pesan kesalahan ini diikuti oleh kesalahan fatal LNK1120. Untuk memperbaiki kesalahan LNK1120, pertama-tama perbaiki semua kesalahan LNK2001 dan LNK2019.

Ada banyak cara untuk mendapatkan kesalahan LNK2001. Semuanya melibatkan referensi ke fungsi atau variabel yang tidak dapat diatasi oleh linker, atau menemukan definisinya. Pengkompilasi dapat mengidentifikasi kapan kode Anda tidak mendeklarasikan simbol, tetapi tidak ketika tidak menentukannya . Itu karena definisi mungkin berada dalam file atau pustaka sumber yang berbeda. Jika kode Anda mengacu pada simbol, tetapi tidak pernah ditentukan, linker menghasilkan kesalahan.

Apa itu simbol eksternal yang belum terselesaikan?

Simbol adalah nama internal untuk fungsi atau variabel global. Ini adalah bentuk nama yang digunakan atau ditentukan dalam file objek atau pustaka yang dikompilasi. Variabel global didefinisikan dalam file objek tempat penyimpanan dialokasikan untuknya. Fungsi didefinisikan dalam file objek tempat kode yang dikompilasi untuk isi fungsi ditempatkan. Simbol eksternal adalah simbol yang dirujuk dalam satu file objek, tetapi didefinisikan dalam pustaka atau file objek yang berbeda. Simbol yang diekspor adalah simbol yang tersedia untuk umum oleh file objek atau pustaka yang menentukannya.

Untuk membuat aplikasi atau DLL, setiap simbol yang digunakan harus memiliki definisi. Linker harus menyelesaikan, atau menemukan definisi yang cocok untuk, setiap simbol eksternal yang dirujuk oleh setiap file objek. Linker menghasilkan kesalahan ketika tidak dapat mengatasi simbol eksternal. Ini berarti linker tidak dapat menemukan definisi simbol yang diekspor yang cocok dalam salah satu file yang ditautkan.

Kesalahan ini dapat terjadi:

  • Ketika proyek kehilangan referensi ke pustaka (. LIB) atau objek (. FILE OBJ). Untuk memperbaiki masalah ini, tambahkan referensi ke pustaka atau file objek yang diperlukan ke proyek Anda. Untuk informasi selengkapnya, lihat File lib sebagai input linker.

  • Ketika proyek memiliki referensi ke pustaka (. LIB) atau objek (. OBJ) file yang pada gilirannya memerlukan simbol dari pustaka lain. Ini dapat terjadi bahkan jika Anda tidak memanggil fungsi yang menyebabkan dependensi. Untuk memperbaiki masalah ini, tambahkan referensi ke pustaka lain ke proyek Anda. Untuk informasi selengkapnya, lihat Memahami model klasik untuk menautkan: Mengambil simbol bersama untuk perjalanan.

  • Jika Anda menggunakan opsi /NODEFAULTLIB atau /Zl . Saat Anda menentukan opsi ini, pustaka yang berisi kode yang diperlukan tidak ditautkan ke dalam proyek kecuali Anda telah secara eksplisit menyertakannya. Untuk memperbaiki masalah ini, sertakan semua pustaka yang Anda gunakan secara eksplisit pada baris perintah tautan. Jika Anda melihat banyak nama fungsi CRT atau Pustaka Standar yang hilang saat Anda menggunakan opsi ini, secara eksplisit sertakan CRT dan DLL Pustaka Standar atau file pustaka di tautan.

  • Jika Anda mengkompilasi menggunakan opsi /clr . Mungkin ada referensi yang hilang ke .cctor. Untuk informasi selengkapnya tentang cara memperbaiki masalah ini, lihat Inisialisasi rakitan campuran.

  • Jika Anda menautkan ke pustaka mode rilis saat membuat versi debug aplikasi. Demikian pula, jika Anda menggunakan opsi /MTd atau /MDd atau menentukan _DEBUG lalu menautkan ke pustaka rilis, Anda harus mengharapkan banyak potensi eksternal yang belum terselesaikan, di antara masalah lainnya. Menautkan build mode rilis dengan pustaka debug juga menyebabkan masalah serupa. Untuk memperbaiki masalah ini, pastikan Anda menggunakan pustaka debug di build debug, dan pustaka ritel di build ritel Anda.

  • Jika kode Anda mengacu pada simbol dari satu versi pustaka, tetapi Anda menautkan versi pustaka yang berbeda. Umumnya, Anda tidak dapat mencampur file objek atau pustaka yang dibuat untuk versi pengkompilasi yang berbeda. Pustaka yang dikirim dalam satu versi mungkin berisi simbol yang tidak dapat ditemukan di pustaka yang disertakan dengan versi lain. Untuk memperbaiki masalah ini, buat semua file objek dan pustaka dengan versi pengkompilasi yang sama sebelum menautkannya bersama-sama. Untuk informasi selengkapnya, lihat Kompatibilitas biner C++ antara versi Visual Studio.

  • Jika jalur pustaka sudah kedaluarsa. Dialog Opsi Alat Proyek VC++ Direktori, di bawah pilihan File pustaka, memungkinkan Anda mengubah urutan pencarian pustaka.> > > Folder Linker dalam kotak dialog Halaman Properti proyek mungkin juga berisi jalur yang bisa kedaluarsa.

  • Ketika Windows SDK baru diinstal (mungkin ke lokasi yang berbeda). Urutan pencarian pustaka harus diperbarui untuk menunjuk ke lokasi baru. Biasanya, Anda harus menempatkan jalur ke direktori SDK baru sertakan dan lib di depan lokasi Visual C++ default. Selain itu, proyek yang berisi jalur yang disematkan mungkin masih menunjuk ke jalur lama yang valid, tetapi kedaluarsa. Perbarui jalur untuk fungsionalitas baru yang ditambahkan oleh versi baru yang diinstal ke lokasi lain.

  • Jika Anda membangun di baris perintah, dan telah membuat variabel lingkungan Anda sendiri. Verifikasi bahwa jalur ke alat, pustaka, dan file header masuk ke versi yang konsisten. Untuk informasi selengkapnya, lihat Menggunakan toolset MSVC dari baris perintah.

Masalah pengkodian

Kesalahan ini dapat disebabkan oleh:

  • Kasus yang tidak cocok dalam kode sumber atau file module-definition (.def) Anda. Misalnya, jika Anda memberi nama variabel var1 dalam satu file sumber C++ dan mencoba mengaksesnya seperti VAR1 di file lain, kesalahan ini dihasilkan. Untuk memperbaiki masalah ini, gunakan nama ejaan dan huruf besar/kecil secara konsisten.

  • Proyek yang menggunakan inlining fungsi. Ini dapat terjadi ketika Anda menentukan fungsi seperti inline dalam file sumber, bukan dalam file header. Fungsi inlined tidak dapat dilihat di luar file sumber yang mendefinisikannya. Untuk memperbaiki masalah ini, tentukan fungsi yang di-inlin di header tempat mereka dideklarasikan.

  • Memanggil fungsi C dari program C++ tanpa menggunakan extern "C" deklarasi untuk fungsi C. Pengkompilasi menggunakan konvensi penamaan simbol internal yang berbeda untuk kode C dan C++. Nama simbol internal adalah apa yang dicari linker saat menyelesaikan simbol. Untuk memperbaiki masalah ini, gunakan extern "C" pembungkus di sekitar semua deklarasi fungsi C yang digunakan dalam kode C++ Anda, yang menyebabkan pengkompilasi menggunakan konvensi penamaan internal C untuk simbol-simbol tersebut. Opsi pengkompilasi /Tp dan /Tc menyebabkan pengkompilasi mengkompilasi file sebagai C++ atau C, masing-masing, apa pun ekstensi nama filenya. Opsi ini dapat menyebabkan nama fungsi internal berbeda dari yang Anda harapkan.

  • Upaya untuk mereferensikan fungsi atau data yang tidak memiliki tautan eksternal. Di C++, fungsi dan const data sebaris memiliki tautan internal kecuali secara eksplisit ditentukan sebagai extern. Untuk memperbaiki masalah ini, gunakan deklarasi eksplisit extern pada simbol yang disebut di luar file sumber yang menentukan.

  • Isi fungsi atau definisi variabel yang hilang. Kesalahan ini umum terjadi saat Anda mendeklarasikan, tetapi jangan tentukan, variabel, fungsi, atau kelas dalam kode Anda. Pengkompilasi hanya memerlukan prototipe fungsi atau extern deklarasi variabel untuk menghasilkan file objek tanpa kesalahan, tetapi linker tidak dapat menyelesaikan panggilan ke fungsi atau referensi ke variabel karena tidak ada kode fungsi atau ruang variabel yang dicadangkan. Untuk memperbaiki masalah ini, pastikan untuk menentukan setiap fungsi dan variabel yang dirujuk dalam file sumber atau pustaka yang Anda tautkan.

  • Panggilan fungsi yang menggunakan jenis pengembalian dan parameter atau konvensi panggilan yang tidak cocok dengan yang ada dalam definisi fungsi. Dalam file objek C++, Dekorasi nama mengodekan konvensi panggilan, cakupan kelas atau namespace layanan, dan mengembalikan dan jenis parameter fungsi. String yang dikodekan menjadi bagian dari nama fungsi yang didekorasi akhir. Nama ini digunakan oleh linker untuk mengatasi, atau mencocokkan, memanggil ke fungsi dari file objek lainnya. Untuk memperbaiki masalah ini, pastikan deklarasi fungsi, definisi, dan panggilan semuanya menggunakan cakupan, jenis, dan konvensi panggilan yang sama.

  • Kode C++ yang Anda panggil, saat Anda menyertakan prototipe fungsi dalam definisi kelas, tetapi jangan sertakan implementasi fungsi. Untuk memperbaiki masalah ini, pastikan untuk memberikan definisi untuk semua anggota kelas yang Anda panggil.

  • Upaya untuk memanggil fungsi virtual murni dari kelas dasar abstrak. Fungsi virtual murni tidak memiliki implementasi kelas dasar. Untuk memperbaiki masalah ini, pastikan semua fungsi virtual yang disebut diimplementasikan.

  • Mencoba menggunakan variabel yang dideklarasikan dalam fungsi (variabel lokal) di luar cakupan fungsi tersebut. Untuk memperbaiki masalah ini, hapus referensi ke variabel yang tidak berada dalam cakupan, atau pindahkan variabel ke cakupan yang lebih tinggi.

  • Saat Anda membuat versi Rilis proyek ATL, menghasilkan pesan bahwa kode startup CRT diperlukan. Untuk memperbaiki masalah ini, lakukan salah satu hal berikut ini,

    • Hapus _ATL_MIN_CRT dari daftar preprocessor mendefinisikan untuk memungkinkan kode startup CRT disertakan. Untuk informasi selengkapnya, lihat Halaman properti umum (Proyek).

    • Jika memungkinkan, hapus panggilan ke fungsi CRT yang memerlukan kode startup CRT. Sebagai gantinya, gunakan setara Win32 mereka. Misalnya, gunakan lstrcmp, bukan strcmp. Fungsi yang diketahui yang memerlukan kode startup CRT adalah beberapa fungsi string dan floating point.

Masalah konsistensi

Saat ini tidak ada standar untuk dekorasi nama C++ antara vendor pengkompilasi, atau bahkan di antara versi yang berbeda dari pengkompilasi yang sama. File objek yang dikompilasi dengan pengkompilasi yang berbeda mungkin tidak menggunakan skema penamaan yang sama. Menautkannya dapat menyebabkan kesalahan LNK2001.

Mencampur opsi kompilasi sebaris dan non-sebaris pada modul yang berbeda dapat menyebabkan LNK2001. Jika pustaka C++ dibuat dengan inlining fungsi diaktifkan (/Ob1 atau /Ob2) tetapi file header yang sesuai yang menjelaskan fungsi telah inlining dimatikan (tidak ada inline kata kunci), kesalahan ini terjadi. Untuk memperbaiki masalah ini, tentukan fungsi inline dalam file header yang Anda sertakan dalam file sumber lainnya.

Jika Anda menggunakan direktif #pragma inline_depth kompilator, pastikan Anda telah menetapkan nilai 2 atau lebih besar, dan pastikan Anda juga menggunakan opsi pengkompilasi /Ob1 atau /Ob2 .

Kesalahan ini dapat terjadi jika Anda menghilangkan opsi LINK /NOENTRY saat Anda membuat DLL khusus sumber daya. Untuk memperbaiki masalah ini, tambahkan opsi /NOENTRY ke perintah tautan.

Kesalahan ini dapat terjadi jika Anda menggunakan pengaturan /SUBSYSTEM atau /ENTRY yang salah dalam proyek Anda. Misalnya, jika Anda menulis aplikasi konsol dan menentukan /SUBSYSTEM:WINDOWS, kesalahan eksternal yang belum terselesaikan dihasilkan untuk WinMain. Untuk memperbaiki masalah ini, pastikan Anda mencocokkan opsi dengan jenis proyek. Untuk informasi selengkapnya tentang opsi dan titik masuk ini, lihat opsi linker /SUBSYSTEM dan /ENTRY .

Masalah simbol file .def yang diekspor

Kesalahan ini terjadi ketika ekspor yang tercantum dalam file .def tidak ditemukan. Bisa jadi karena ekspor tidak ada, dieja dengan salah, atau menggunakan nama yang didekorasi C++. File .def tidak mengambil nama yang didekorasi. Untuk memperbaiki masalah ini, hapus ekspor yang tidak perlu, dan gunakan extern "C" deklarasi untuk simbol yang diekspor.

Gunakan nama yang didekorasi untuk menemukan kesalahan

Pengkompilasi dan linker C++ menggunakan Dekorasi Nama, juga dikenal sebagai name-mangling. Dekorasi nama mengodekan informasi tambahan tentang jenis variabel dalam nama simbolnya. Nama simbol untuk fungsi mengodekan jenis pengembaliannya, jenis parameter, cakupan, dan konvensi panggilan. Nama yang didekorasi ini adalah nama simbol yang dicari linker untuk mengatasi simbol eksternal.

Kesalahan tautan dapat mengakibatkan deklarasi fungsi atau variabel tidak sama persis dengan definisi fungsi atau variabel. Itu karena perbedaan apa pun menjadi bagian dari nama simbol yang cocok. Kesalahan dapat terjadi bahkan jika file header yang sama digunakan dalam kode panggilan dan kode yang menentukan. Salah satu cara yang mungkin terjadi adalah jika Anda mengkompilasi file sumber dengan menggunakan bendera pengkompilasi yang berbeda. Misalnya, jika kode Anda dikompilasi untuk menggunakan __vectorcall konvensi panggilan, tetapi Anda menautkan ke pustaka yang mengharapkan klien memanggilnya menggunakan konvensi default __cdecl atau __fastcall panggilan. Dalam hal ini, simbol tidak cocok karena konvensi panggilan berbeda.

Untuk membantu Anda menemukan penyebabnya, pesan kesalahan menunjukkan dua versi nama. Ini menampilkan "nama yang mudah diingat", nama yang digunakan dalam kode sumber, dan nama yang didekorasi (dalam tanda kurung). Anda tidak perlu tahu cara menafsirkan nama yang didekorasi. Anda masih dapat mencari dan membandingkannya dengan nama lain yang dihiasi. Alat baris perintah dapat membantu menemukan dan membandingkan nama simbol yang diharapkan dan nama simbol aktual:

  • Opsi /EXPORTS dan /SYMBOLS dari alat baris perintah DUMPBIN berguna di sini. Mereka dapat membantu Anda menemukan simbol mana yang ditentukan dalam file .dll dan objek atau pustaka Anda. Anda dapat menggunakan daftar simbol untuk memverifikasi bahwa nama yang didekorasi yang diekspor cocok dengan nama yang didekorasi yang dicari linker.

  • Dalam beberapa kasus, linker hanya dapat melaporkan nama yang didekorasi untuk simbol. Anda dapat menggunakan alat baris perintah UNDNAME untuk mendapatkan bentuk nama yang tidak terdekorasi.

Sumber Daya Tambahan:

Untuk informasi selengkapnya, lihat pertanyaan Stack Overflow "Apa itu referensi yang tidak ditentukan/kesalahan simbol eksternal yang tidak terselesaikan dan bagaimana cara memperbaikinya?".