undefinierter Verweis auf "WinMain @ 16"

110

Wenn ich versuche, ein Programm mit zu erstellen Eclipse CDT, erhalte ich Folgendes:

/mingw/lib/libmingw32.a(main.o):main.c:(.text+0x106): undefinierter Verweis auf `WinMain @ 16

Warum ist das so? Und wie kann ich dieses Problem lösen?

Einfachheit
quelle

Antworten:

183

Betrachten Sie das folgende Programm auf Windows-API-Ebene:

#define NOMINMAX
#include <windows.h>

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

Jetzt erstellen wir es mit der GNU-Toolchain (dh g ++), ohne spezielle Optionen. Hiergnuc ist nur eine Batch-Datei, die ich dafür verwende. Es bietet nur Optionen, um g ++ standardisierter zu machen:

C: \ test> gnuc x.cpp

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

C: \ test> _

Dies bedeutet, dass der Linker standardmäßig eine ausführbare Konsolensubsystemdatei erstellt hat . Der Subsystemwert im Dateikopf teilt Windows mit, welche Dienste das Programm benötigt. In diesem Fall benötigt das Programm beim Konsolensystem ein Konsolenfenster.

Dies führt auch dazu, dass der Befehlsinterpreter auf den Abschluss des Programms wartet.

Jetzt erstellen wir es mit dem GUI-Subsystem , was nur bedeutet, dass das Programm kein Konsolenfenster benötigt:

C: \ test> gnuc x.cpp -mwindows

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

C: \ test> _

Hoffentlich ist das soweit in Ordnung, obwohl die -mwindowsFlagge nur halb dokumentiert ist.

Ohne dieses halbdokumentierte Flag müsste man dem Linker genauer mitteilen, welchen Subsystemwert er wünscht, und einige Windows-API-Importbibliotheken müssen dann im Allgemeinen explizit angegeben werden:

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

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

C: \ test> _

Mit der GNU-Toolchain hat das gut funktioniert.

Aber was ist mit der Microsoft-Toolchain, dh Visual C ++?

Das Erstellen als ausführbare Datei für ein Konsolensubsystem funktioniert einwandfrei:

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

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

C: \ test> _

Bei der Erstellung der Microsoft-Toolchain als GUI-Subsystem funktioniert dies jedoch nicht standardmäßig:

C: \ test> msvc x.cpp user32.lib / link / subsystem: windows
x.cpp
LIBCMT.lib (wincrt0.obj): Fehler LNK2019: ungelöstes externes Symbol _WinMain @ 16, auf das in der Funktion ___tmainCRTStartu verwiesen wird
p
x.exe: Schwerwiegender Fehler LNK1120: 1 ungelöste externe Daten

C: \ test> _

Technisch gesehen liegt dies daran, dass der Linker von Microsoft für das GUI-Subsystem standardmäßig nicht dem Standard entspricht . Wenn das Subsystem eine grafische Benutzeroberfläche ist, verwendet der Linker von Microsoft standardmäßig einen Einstiegspunkt für die Laufzeitbibliothek , die Funktion, bei der die Ausführung des Maschinencodes beginnt. Diese Funktion winMainCRTStartupruft den Nicht-Standard WinMainvon Microsoft anstelle des Standards auf main.

Keine große Sache, um das zu beheben.

Alles, was Sie tun müssen, ist dem Linker von Microsoft mitzuteilen, welcher Einstiegspunkt verwendet werden soll, nämlich mainCRTStartupwelcher Standardaufruf main:

C: \ test> msvc x.cpp user32.lib / link / subsystem: windows / entry: mainCRTStartup
x.cpp

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

C: \ test> _

Kein Problem, aber sehr langweilig. Und so geheimnisvoll und verborgen, dass die meisten Windows-Programmierer, die meist nur die standardmäßig nicht standardmäßigen Tools von Microsoft verwenden, nicht einmal davon wissen und fälschlicherweise glauben, dass ein Windows-GUI-Subsystemprogramm nicht standardmäßig, WinMainsondern standardmäßig sein muss main. Im Übrigen wird Microsoft mit C ++ 0x ein Problem damit haben, da der Compiler dann bekannt geben muss, ob er freistehend oder gehostet ist (wenn er gehostet wird, muss er Standard unterstützen main).

Dies ist der Grund, warum sich g ++ über das Fehlen beschweren kannWinMain : Es ist eine alberne, nicht standardmäßige Startfunktion, die die Microsoft-Tools standardmäßig für GUI-Subsystemprogramme benötigen.

Wie Sie oben sehen können, hat g ++ mainselbst für ein GUI-Subsystemprogramm kein Problem mit dem Standard .

Was könnte das Problem sein?

Nun, Sie vermissen wahrscheinlich eine main. Und Sie haben wahrscheinlich auch keine (richtige) WinMain! Und dann meldet g ++ nach der Suche nach main(kein solches) und nach Microsofts Nicht-Standard WinMain(kein solches), dass letzteres fehlt.

Testen mit einer leeren Quelle:

C: \ test> Typ nul> y.cpp

C: \ test> gnuc y.cpp -mwindows
c: / program files / mingw / bin /../ lib / gcc / mingw32 / 4.4.1 /../../../ libmingw32.a (main.o): main.c :(. text + 0xd2 ): undefinierte referen
ce zu `WinMain @ 16 '
collect2: ld hat 1 Exit-Status zurückgegeben

C: \ test> _
Prost und hth. - Alf
quelle
3
@ Alf P. Steinbach. Vielen Dank für Ihre nette Antwort. Wie für All you have to do is to tell Microsoft's linker which entry point to use, namely mainCRTStartup, which calls standard main. Gibt es eine Möglichkeit, dies zu tun, Eclipse CDTda ich die Befehlszeile nicht verwende? Danke
Einfachheit
1
@ user588855: Da Sie g ++ verwenden, gilt dies (wahrscheinlich) nicht für Sie. Es gilt (wahrscheinlich) nur der Teil am Ende. Definieren Sie also a mainoder a WinMainoder stellen Sie sicher, dass die entsprechende Datei im Projekt enthalten ist. Prost,
Prost und hth. - Alf
@ Alf P. Steinbach. Was meinst du mit definieren mainoder winmain? Danke
Einfachheit
1
Ich habe gerade eine Datei namens main.cpp erstellt, die den folgenden Code hatte: int main () {}
In der Tat
3
Ich wäre nett, wenn jeder Downvoter die Downvote erklären könnte. Möglicherweise haben andere Leser das gleiche Missverständnis (was auch immer es ist), und dann könnten wir das klären. Jeder würde davon profitieren, anstatt irregeführt zu werden. Bitte erläutern Sie Ihre Ablehnung. Danke dir.
Prost und hth. - Alf
68

Um den obigen Beitrag von Cheers und hth zusammenzufassen. - Alf, stellen Sie sicher, dass Sie haben main()oder WinMain()definiert haben und g ++ sollte das Richtige tun.

Mein Problem war, dass main()es versehentlich in einem Namespace definiert wurde.

Tim Ludwinski
quelle
Ich habe gerade etwas Wichtiges an all dem erkannt. In meinem Fall wurde main () nicht gefunden, da ich keine Argumente deklariert habe (argc, argv). Einmal hinzugefügt, fand es main. Die Art und Weise, wie dies funktioniert, bedeutet auch, dass mingw versucht zu helfen, indem es eine eigene Hauptleitung bereitstellt, die wiederum WinMain aufruft. GUI-Programme hätten nur WinMain und der Hauptstub in mingw wird verwendet, um dorthin zu gelangen. Wenn Sie eine Hauptleitung haben, wird diese stattdessen verwendet.
Jeff Muir
extern "C" int main (void) hat das Problem für mich behoben
behoben
33

Beim Kompilieren meiner Anwendung mit SDL ist dieser Fehler aufgetreten. Dies wurde dadurch verursacht, dass SDL seine eigene Hauptfunktion in SDL_main.h definiert. Um zu verhindern, dass SDL die Hauptfunktion definiert, muss ein SDL_MAIN_HANDLED-Makro definiert werden, bevor der SDL.h-Header enthalten ist.

X-Frox
quelle
Gute Antwort! +1
Mohammad Kanan
Vielen Dank! Dieser Befehl funktioniert: 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

Versuchen Sie, Ihre .c-Datei vor dem Erstellen zu speichern. Ich glaube, Ihr Computer verweist auf einen Pfad zu einer Datei, in der sich keine Informationen befinden.

- Hatte ein ähnliches Problem beim Erstellen von C-Projekten

JabbaJava
quelle
Dadurch wurde mein Problem tatsächlich behoben, und ich hinterlasse diesen Kommentar, um mehr Aufmerksamkeit zu erlangen.
David Chen
0

Überprüfen Sie, ob alle Dateien in Ihrem Projekt enthalten sind:

Nach der Aktualisierung von cLion wurde derselbe Fehler angezeigt. Nach stundenlangem Basteln bemerkte ich, dass eine meiner Dateien nicht im Projektziel enthalten war. Nachdem ich es wieder zum aktiven Projekt hinzugefügt hatte, wurde der undefinierte Verweis auf winmain16 nicht mehr abgerufen und der Code kompiliert.

Bearbeiten: Es lohnt sich auch, die Build-Einstellungen in Ihrer IDE zu überprüfen.

(Ich bin mir nicht sicher, ob dieser Fehler mit der kürzlich erfolgten Aktualisierung der IDE zusammenhängt - könnte kausal oder einfach korrelativ sein.


quelle