referensi tak terdefinisi ke `WinMain @ 16 '

110

Ketika saya mencoba membuat program menggunakan Eclipse CDT, saya mendapatkan yang berikut:

/mingw/lib/libmingw32.a(main.o):main.c:(.text+0x106): referensi tidak ditentukan ke `WinMain @ 16

Mengapa demikian? Dan, bagaimana saya bisa mengatasi masalah ini?

Kesederhanaan
sumber

Jawaban:

184

Pertimbangkan program level API Windows berikut:

#define NOMINMAX
#include <windows.h>

int main()
{
    MessageBox( 0, "Blah blah...", "My Windows app!", MB_SETFOREGROUND );
}

Sekarang mari kita membangunnya menggunakan GNU toolchain (yaitu g ++), tanpa opsi khusus. Ini gnuchanya file batch yang saya gunakan untuk itu. Ini hanya menyediakan opsi untuk membuat g ++ lebih standar:

C: \ test> gnuc x.cpp

C: \ test> objdump -x a.exe | findstr / i "^ subsistem"
Subsistem 00000003 (Windows CUI)

C: \ test> _

Ini berarti bahwa linker secara default menghasilkan subsistem konsol yang dapat dieksekusi. Nilai subsistem di header file memberi tahu Windows layanan apa yang dibutuhkan program. Dalam hal ini, dengan sistem konsol, program tersebut memerlukan jendela konsol.

Ini juga menyebabkan penerjemah perintah menunggu program selesai.

Sekarang mari kita membangunnya dengan subsistem GUI , yang artinya program tidak memerlukan jendela konsol:

C: \ test> gnuc x.cpp -mwindows

C: \ test> objdump -x a.exe | findstr / i "^ subsistem"
Subsistem 00000002 (Windows GUI)

C: \ test> _

Mudah-mudahan tidak apa-apa sejauh ini, meskipun -mwindowsbenderanya hanya setengah terdokumentasi.

Membangun tanpa bendera semi-terdokumentasi itu, seseorang harus lebih spesifik memberi tahu linker nilai subsistem mana yang diinginkan, dan beberapa pustaka impor Windows API secara umum harus ditentukan secara eksplisit:

C: \ test> gnuc x.cpp -Wl, -subsystem, windows

C: \ test> objdump -x a.exe | findstr / i "^ subsistem"
Subsistem 00000002 (Windows GUI)

C: \ test> _

Itu bekerja dengan baik, dengan toolchain GNU.

Tapi bagaimana dengan toolchain Microsoft, yaitu Visual C ++?

Nah, membangun sebagai subsistem konsol yang dapat dieksekusi berfungsi dengan baik:

C: \ test> pnidui x.cpp user32.lib
x.cpp

C: \ test> dumpbin / headers x.exe | temukan / i "subsistem" | temukan / i "Windows"
               3 subsistem (Windows CUI)

C: \ test> _

Namun, dengan pembangunan toolchain Microsoft sebagai subsistem GUI tidak berfungsi secara default:

C: \ test> pnidui x.cpp user32.lib / link / subsistem: windows
x.cpp
LIBCMT.lib (wincrt0.obj): error LNK2019: simbol eksternal belum terselesaikan _WinMain @ 16 direferensikan dalam fungsi ___tmainCRTStartu
p
x.exe: kesalahan fatal LNK1120: 1 eksternal yang belum terselesaikan

C: \ test> _

Secara teknis ini karena linker Microsoft non-standar secara default untuk subsistem GUI . Secara default, jika subsistemnya adalah GUI, maka linker Microsoft menggunakan titik masuk pustaka runtime , fungsi tempat eksekusi kode mesin dimulai, disebut winMainCRTStartup, yang memanggil non-standar Microsoft, WinMainbukan standar main.

Bukan masalah besar untuk memperbaikinya.

Yang harus Anda lakukan adalah memberi tahu tautan Microsoft titik masuk mana yang akan digunakan, yaitu mainCRTStartupyang memanggil standar main:

C: \ test> pnidui x.cpp user32.lib / link / subsistem: windows / entry: mainCRTStartup
x.cpp

C: \ test> dumpbin / headers x.exe | temukan / i "subsistem" | temukan / i "Windows"
               2 subsistem (Windows GUI)

C: \ test> _

Tidak masalah, tapi sangat membosankan. Dan begitu misterius dan tersembunyi sehingga sebagian besar programmer Windows, yang kebanyakan hanya menggunakan alat non-standar-oleh-default Microsoft, bahkan tidak mengetahuinya, dan secara keliru berpikir bahwa program subsistem GUI Windows “harus” memiliki non-standar dan WinMainbukan standar main. Secara sepintas, dengan C ++ 0x Microsoft akan memiliki masalah dengan ini, karena kompiler harus mengiklankan apakah itu berdiri bebas atau dihosting (ketika dihosting harus mendukung standar main).

Bagaimanapun, itulah alasan mengapa g ++ dapat mengeluh tentang WinMainhilang: ini adalah fungsi startup non-standar yang konyol yang diperlukan alat Microsoft secara default untuk program subsistem GUI.

Tetapi seperti yang Anda lihat di atas, g ++ tidak memiliki masalah dengan standar mainbahkan untuk program subsistem GUI.

Jadi apa masalahnya?

Nah, Anda mungkin melewatkan file main. Dan Anda mungkin juga tidak memiliki (yang layak) WinMain! Dan kemudian g ++, setelah mencari main(tidak ada), dan non-standar Microsoft WinMain(tidak seperti itu), melaporkan bahwa yang terakhir hilang.

Menguji dengan sumber kosong:

C: \ test> ketik nul> y.cpp

C: \ test> gnuc y.cpp -mwindows
c: / berkas program / mingw / bin /../ lib / gcc / mingw32 / 4.4.1 /../../../ libmingw32.a (main.o): main.c :(. teks + 0xd2 ): rujukan yang tidak ditentukan
ce ke `WinMain @ 16 '
collect2: ld mengembalikan 1 status keluar

C: \ test> _
Cheers and hth. - Alf
sumber
3
@Tokopedia Terima kasih banyak atas balasan Anda yang bagus. Adapun All you have to do is to tell Microsoft's linker which entry point to use, namely mainCRTStartup, which calls standard main. Apakah ada cara untuk melakukan itu Eclipse CDTkarena saya tidak menggunakan baris perintah. Terima kasih
Simplicity
1
@ user588855: karena Anda menggunakan g ++ yang (mungkin) tidak berlaku untuk Anda. Hanya bagian di akhir (mungkin) yang berlaku. Yaitu, definisikan a mainatau a WinMain, atau, pastikan bahwa file yang relevan disertakan dalam proyek. Cheers,
Cheers and hth. - Alf
@Tokopedia Apa yang Anda maksud dengan mendefinisikan mainatau winmain? Terima kasih
Simplicity
1
Saya baru saja membuat file bernama main.cpp yang memiliki kode: int main () {}
Memang
3
Saya akan senang jika setiap downvoter dapat menjelaskan downvote tersebut. Karena mungkin pembaca lain memiliki kesalahpahaman yang sama (apapun itu), dan kemudian kita bisa menjelaskannya. Setiap orang akan mendapat manfaat, bukannya disesatkan. Jadi, mohon jelaskan downvote Anda. Terima kasih.
Cheers and hth. - Alf
68

Untuk meringkas posting di atas oleh Cheers dan hth. - Alf, Pastikan Anda memiliki main()atau WinMain()mendefinisikan dan g ++ harus melakukan hal yang benar.

Masalah saya adalah yang main()didefinisikan di dalam namespace secara tidak sengaja.

Tim Ludwinski
sumber
Baru menyadari sesuatu yang penting tentang semua ini. Dalam kasus saya, itu tidak menemukan main () karena saya tidak mendeklarasikan argumen (argc, argv). Setelah ditambahkan, itu ditemukan utama. Juga, sifat dari cara kerjanya berarti bahwa mingw mencoba membantu dengan menyediakan utamanya sendiri yang pada gilirannya memanggil WinMain. Program GUI hanya memiliki WinMain dan stub utama di mingw digunakan untuk mencapainya. Jika Anda memiliki induk, maka ia menggunakan itu sebagai gantinya.
Jeff Muir
extern "C" int main (void) memperbaiki masalah saya
dryler
33

Saya mengalami kesalahan ini saat menyusun aplikasi saya dengan SDL. Hal ini disebabkan oleh SDL yang mendefinisikan fungsi utamanya sendiri di SDL_main.h. Untuk mencegah SDL menentukan fungsi utama, makro SDL_MAIN_HANDLED harus ditentukan sebelum header SDL.h disertakan.

X-Frox
sumber
Jawaban yang bagus! +1
Mohammad Kanan
Terima kasih banyak! Perintah ini berfungsi: gcc main.c -I "E: \ Libs \ SDL2-devel-2.0.12-mingw \ SDL2-2.0.12 \ i686-w64-mingw32 \ include" -I "E: \ Libs \ SDL2_ttf- devel-2.0.15-mingw \ SDL2_ttf-2.0.15 \ i686-w64-mingw32 \ include "-L" E: \ Libs \ SDL2-devel-2.0.12-mingw \ SDL2-2.0.12 \ i686-w64- mingw32 \ lib "-L" E: \ Libs \ SDL2_ttf-devel-2.0.15-mingw \ SDL2_ttf-2.0.15 \ i686-w64-mingw32 \ lib "-lSDL2 -lSDL2main -lSDL2_ttf -o app.exe
8Observer8
5

Coba simpan file .c Anda sebelum membangun. Saya yakin komputer Anda mereferensikan jalur ke file tanpa informasi di dalamnya.

--Memiliki masalah serupa saat membangun proyek C.

JabbaJava
sumber
Ini benar-benar menyelesaikan masalah saya, dan saya meninggalkan komentar ini untuk membantunya mendapatkan lebih banyak perhatian.
David Chen
0

Periksa bahwa Semua File Disertakan dalam Proyek Anda:

Saya mengalami kesalahan yang sama muncul setelah saya memperbarui cLion. Setelah berjam-jam mengutak-atik, saya melihat salah satu file saya tidak termasuk dalam target proyek. Setelah saya menambahkannya kembali ke proyek aktif, saya berhenti mendapatkan referensi yang tidak ditentukan ke winmain16, dan kode dikompilasi.

Edit: Ini juga bermanfaat untuk memeriksa pengaturan build dalam IDE Anda.

(Tidak yakin apakah kesalahan ini terkait dengan pembaruan IDE - bisa jadi kausal atau korelatif. Jangan ragu untuk berkomentar dengan pemahaman apa pun tentang faktor itu!)


sumber