référence indéfinie à `WinMain @ 16 '

110

Lorsque j'essaie de créer un programme en utilisant Eclipse CDT, j'obtiens ce qui suit:

/mingw/lib/libmingw32.a(main.o):main.c:(.text+0x106): référence non définie à `WinMain @ 16

Pourquoi donc? Et comment puis-je résoudre ce problème?

Simplicité
la source

Réponses:

184

Considérez le programme de niveau API Windows suivant:

#define NOMINMAX
#include <windows.h>

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

Maintenant, construisons-le en utilisant la chaîne d'outils GNU (ie g ++), pas d'options spéciales. Voici gnucjuste un fichier batch que j'utilise pour cela. Il ne fournit que des options pour rendre g ++ plus standard:

C: \ test> gnuc x.cpp

C: \ test> objdump -x a.exe | findstr / i "^ sous-système"
Sous-système 00000003 (Windows CUI)

C: \ test> _

Cela signifie que l'éditeur de liens a produit par défaut un exécutable de sous-système de console . La valeur du sous-système dans l'en-tête du fichier indique à Windows les services dont le programme a besoin. Dans ce cas, avec le système de console, que le programme nécessite une fenêtre de console.

Cela oblige également l'interpréteur de commandes à attendre la fin du programme.

Maintenant, construisons-le avec le sous - système GUI , ce qui signifie simplement que le programme ne nécessite pas de fenêtre de console:

C: \ test> gnuc x.cpp -mwindows

C: \ test> objdump -x a.exe | findstr / i "^ sous-système"
Sous-système 00000002 (interface graphique Windows)

C: \ test> _

Espérons que ce soit OK jusqu'à présent, bien que le -mwindowsdrapeau soit juste semi-documenté.

Construire sans cet indicateur semi-documenté, il faudrait indiquer plus spécifiquement à l'éditeur de liens la valeur de sous-système souhaitée, et certaines bibliothèques d'importation d'API Windows devront alors en général être spécifiées explicitement:

C: \ test> gnuc x.cpp -Wl, -subsystem, fenêtres

C: \ test> objdump -x a.exe | findstr / i "^ sous-système"
Sous-système 00000002 (interface graphique Windows)

C: \ test> _

Cela a bien fonctionné, avec la chaîne d'outils GNU.

Mais qu'en est-il de la chaîne d'outils Microsoft, c'est-à-dire Visual C ++?

Eh bien, la construction en tant qu'exécutable de sous-système de console fonctionne bien:

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

C: \ test> dumpbin / headers x.exe | find / i "sous-système" | trouver / i "Windows"
               3 sous-système (Windows CUI)

C: \ test> _

Cependant, avec la construction de la chaîne d'outils de Microsoft en tant que sous-système GUI, ne fonctionne pas par défaut:

C: \ test> msvc x.cpp user32.lib / link / subsystem: windows
x.cpp
LIBCMT.lib (wincrt0.obj): erreur LNK2019: symbole externe non résolu _WinMain @ 16 référencé dans la fonction ___tmainCRTStartu
p
x.exe: erreur fatale LNK1120: 1 externes non résolus

C: \ test> _

Techniquement, c'est parce que l'éditeur de liens de Microsoft n'est pas standard par défaut pour le sous-système GUI . Par défaut, lorsque le sous-système est GUI, l'éditeur de liens de Microsoft utilise un point d'entrée de bibliothèque d'exécution , la fonction où commence l'exécution du code machine, appelée winMainCRTStartup, qui appelle Microsoft non standard WinMainau lieu de standard main.

Pas grand-chose à résoudre, cependant.

Tout ce que vous avez à faire est d'indiquer à l'éditeur de liens de Microsoft le point d'entrée à utiliser, à savoir mainCRTStartup, qui appelle standard main:

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

C: \ test> dumpbin / headers x.exe | find / i "sous-système" | trouver / i "Windows"
               2 sous-système (interface graphique Windows)

C: \ test> _

Pas de problème, mais très fastidieux. Et si obscur et caché que la plupart des programmeurs Windows, qui utilisent uniquement les outils non standard par défaut de Microsoft, ne le savent même pas et pensent à tort qu'un programme de sous-système Windows GUI «doit» avoir non standard WinMainau lieu de standard main. En passant, avec C ++ 0x, Microsoft aura un problème avec cela, car le compilateur doit alors annoncer s'il est autonome ou hébergé (lorsqu'il est hébergé, il doit prendre en charge le standard main).

Quoi qu'il en soit, c'est la raison pour laquelle g ++ peut se plaindre de son WinMainabsence: c'est une fonction de démarrage non standard idiote dont les outils Microsoft ont besoin par défaut pour les programmes de sous-système GUI.

Mais comme vous pouvez le voir ci-dessus, g ++ n'a aucun problème avec le standard, mainmême pour un programme de sous-système GUI.

Alors quel pourrait être le problème?

Eh bien, il vous manque probablement un fichiermain . Et vous n'en avez probablement pas non WinMainplus! Et puis g ++, après avoir recherché main(pas de tel), et non standard de Microsoft WinMain(pas de tel), rapporte que ce dernier est manquant.

Test avec une source vide:

C: \ test> type 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 :(. texte + 0xd2 ): référence non définie
ce à `WinMain @ 16 '
collect2: ld a renvoyé 1 statut de sortie

C: \ test> _
Bravo et hth. - Alf
la source
3
@Alf P. Steinbach. Merci beaucoup pour votre gentille réponse. Quant à All you have to do is to tell Microsoft's linker which entry point to use, namely mainCRTStartup, which calls standard main. Existe-t-il un moyen de le faire Eclipse CDTcar je n'utilise pas la ligne de commande. Merci
Simplicité
1
@ user588855: puisque vous utilisez g ++, cela ne s'applique (probablement) pas à vous. Seule la partie à la fin s'applique (probablement). Autrement dit, définissez un mainou un WinMain, ou, assurez-vous que le fichier pertinent est inclus dans le projet. Cheers,
Cheers et hth. - Alf
@Alf P. Steinbach. Qu'entendez-vous par définition mainou winmain? Merci
Simplicité
1
Je viens de créer un fichier appelé main.cpp qui avait le code: int main () {}
En effet
3
Je serais bien si chaque contrevenant pouvait expliquer le vote négatif. Car peut-être d'autres lecteurs ont la même idée fausse (quelle qu'elle soit), et alors nous pourrions clarifier cela. Tout le monde en profiterait, au lieu que certains soient induits en erreur. Alors, expliquez votre vote défavorable. Je vous remercie.
Acclamations et hth. - Alf
68

Pour résumer le post ci-dessus par Cheers et hth. - Alf, assurez-vous que vous avez défini main()ou WinMain()défini et que g ++ devrait faire ce qu'il faut.

Mon problème était que cela a main()été défini à l'intérieur d'un espace de noms par accident.

Tim Ludwinski
la source
Je viens de réaliser quelque chose d'important à propos de tout cela. Dans mon cas, il ne trouvait pas main () puisque je n'ai déclaré aucun argument (argc, argv). Une fois ajouté, il a trouvé principal. En outre, la nature de la façon dont cela fonctionne signifie que mingw essaie d'aider en fournissant son propre main qui à son tour appelle WinMain. Les programmes GUI n'auraient que WinMain et le stub principal de mingw est utilisé pour y arriver. Si vous avez un main, il l'utilise à la place.
Jeff Muir
extern "C" int main (void) a corrigé le problème pour moi
dryler
33

Je rencontrais cette erreur lors de la compilation de mon application avec SDL. Cela était dû au fait que SDL définissait sa propre fonction principale dans SDL_main.h. Pour empêcher SDL de définir la fonction principale, une macro SDL_MAIN_HANDLED doit être définie avant que l'en-tête SDL.h ne soit inclus.

X-Frox
la source
Très bonne réponse! +1
Mohammad Kanan
Merci beaucoup! Cette commande fonctionne: 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

Essayez d'enregistrer votre fichier .c avant de créer. Je crois que votre ordinateur fait référence à un chemin vers un fichier sans aucune information à l'intérieur.

--A eu un problème similaire lors de la construction de projets C

JabbaJava
la source
Cela a en fait résolu mon problème, et je laisse ce commentaire pour l'aider à attirer plus d'attention.
David Chen
0

Vérifiez que tous les fichiers sont inclus dans votre projet:

J'ai eu cette même erreur après avoir mis à jour cLion. Après des heures de bricolage, j'ai remarqué qu'un de mes fichiers n'était pas inclus dans la cible du projet. Après l'avoir ajouté au projet actif, j'ai arrêté d'obtenir la référence non définie à winmain16 et le code compilé.

Modifier: il vaut également la peine de vérifier les paramètres de construction dans votre IDE.

(Je ne sais pas si cette erreur est liée à la mise à jour récente de l'EDI - pourrait être causale ou simplement corrélative. N'hésitez pas à commenter avec un aperçu de ce facteur!)


la source