referencia indefinida a 'WinMain @ 16'

110

Cuando trato de construir un programa usando Eclipse CDT, obtengo lo siguiente:

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

¿Porqué es eso? ¿Y cómo puedo solucionar este problema?

Sencillez
fuente

Respuestas:

184

Considere el siguiente programa de nivel de API de Windows:

#define NOMINMAX
#include <windows.h>

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

Ahora vamos a construirlo usando la cadena de herramientas GNU (es decir, g ++), sin opciones especiales. Aquí gnuchay solo un archivo por lotes que utilizo para eso. Solo proporciona opciones para hacer que g ++ sea más estándar:

C: \ prueba> gnuc x.cpp

C: \ prueba> objdump -x a.exe | Findstr / i "^ subsistema"
Subsistema 00000003 (CUI de Windows)

C: \ prueba> _

Esto significa que el enlazador produjo de forma predeterminada un ejecutable del subsistema de consola . El valor del subsistema en el encabezado del archivo le dice a Windows qué servicios requiere el programa. En este caso, con sistema de consola, el programa requiere una ventana de consola.

Esto también hace que el intérprete de comandos espere a que se complete el programa.

Ahora construyémoslo con el subsistema GUI , lo que solo significa que el programa no requiere una ventana de consola:

C: \ prueba> gnuc x.cpp -mwindows

C: \ prueba> objdump -x a.exe | Findstr / i "^ subsistema"
Subsistema 00000002 (GUI de Windows)

C: \ prueba> _

Con suerte, eso está bien hasta ahora, aunque la -mwindowsbandera está semidocumentada.

Construyendo sin esa bandera semidocumentada, uno tendría que decirle más específicamente al vinculador qué valor de subsistema se desea, y algunas bibliotecas de importación de API de Windows, en general, deberán especificarse explícitamente:

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

C: \ prueba> objdump -x a.exe | Findstr / i "^ subsistema"
Subsistema 00000002 (GUI de Windows)

C: \ prueba> _

Eso funcionó bien, con la cadena de herramientas GNU.

Pero, ¿qué pasa con la cadena de herramientas de Microsoft, es decir, Visual C ++?

Bueno, la construcción como un ejecutable de subsistema de consola funciona bien:

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

C: \ prueba> dumpbin / headers x.exe | buscar / i "subsistema" | buscar / i "Windows"
               3 subsistema (CUI de Windows)

C: \ prueba> _

Sin embargo, con la construcción de la cadena de herramientas de Microsoft como subsistema de GUI no funciona de forma predeterminada:

C: \ prueba> msvc x.cpp user32.lib / link / subsystem: windows
x.cpp
LIBCMT.lib (wincrt0.obj): error LNK2019: símbolo externo no resuelto _WinMain @ 16 referenciado en la función ___tmainCRTStartu
pags
x.exe: error fatal LNK1120: 1 externos sin resolver

C: \ prueba> _

Técnicamente, esto se debe a que el enlazador de Microsoft no es estándar por defecto para el subsistema GUI . De forma predeterminada, cuando el subsistema es GUI, entonces el enlazador de Microsoft usa un punto de entrada de biblioteca en tiempo de ejecución , la función donde comienza la ejecución del código de máquina, llamada winMainCRTStartup, que llama a Microsoft no estándar en WinMainlugar de estándar main.

Sin embargo, no es gran cosa arreglar eso.

Todo lo que tiene que hacer es decirle al vinculador de Microsoft qué punto de entrada usar, es decir mainCRTStartup, cuál llama estándar main:

C: \ prueba> msvc x.cpp user32.lib / link / subsystem: windows / entrada: mainCRTStartup
x.cpp

C: \ prueba> dumpbin / headers x.exe | buscar / i "subsistema" | buscar / i "Windows"
               2 subsistema (GUI de Windows)

C: \ prueba> _

No hay problema, pero muy tedioso. Y tan arcano y oculto que la mayoría de los programadores de Windows, que en su mayoría solo usan las herramientas no estándar por defecto de Microsoft, ni siquiera lo saben, y piensan erróneamente que un programa de subsistema de GUI de Windows "debe" tener un programa no estándar en WinMainlugar de estándar. main. De paso, con C ++ 0x Microsoft tendrá un problema con esto, ya que el compilador debe anunciar si es independiente o alojado (cuando está alojado debe ser compatible con el estándar main).

De todos modos, esa es la razón por la que g ++ puede quejarse de la WinMainfalta: es una función de inicio tonta y no estándar que las herramientas de Microsoft requieren por defecto para los programas del subsistema GUI.

Pero como puede ver arriba, g ++ no tiene ningún problema con el estándar, mainincluso para un programa de subsistema GUI.

Entonces, ¿Cuál podría ser el problema?

Bueno, probablemente te falte un main. ¡Y probablemente tampoco tengas (adecuado) WinMain! Y luego g ++, después de haber buscado main(no such), y de Microsoft no estándar WinMain(no such), informa que falta este último.

Prueba con una fuente vacía:

C: \ prueba> escriba nul> y.cpp

C: \ prueba> gnuc y.cpp -mwindows
c: / archivos de programa / mingw / bin /../ lib / gcc / mingw32 / 4.4.1 /../../../ libmingw32.a (main.o): main.c :(. text + 0xd2 ): referencia indefinida
ce a 'WinMain @ 16'
collect2: ld devolvió 1 estado de salida

C: \ prueba> _
Saludos y hth. - Alf
fuente
3
@ Alf P. Steinbach. Muchas gracias por tu linda respuesta. En cuanto a All you have to do is to tell Microsoft's linker which entry point to use, namely mainCRTStartup, which calls standard main. ¿Hay alguna manera de hacerlo Eclipse CDTya que no estoy usando la línea de comando? Gracias
Simplicity
1
@ user588855: dado que está usando g ++, eso (probablemente) no se aplica a usted. Solo se aplica la parte al final (probablemente). Es decir, defina un maino un WinMain, o asegúrese de que el archivo relevante esté incluido en el proyecto. Saludos,
Saludos y hth. - Alf
@ Alf P. Steinbach. ¿A qué te refieres con definir maino winmain? Gracias
Simplicity
1
Acabo de crear un archivo llamado main.cpp que tenía el código: int main () {}
De hecho,
3
Sería bueno si cada votante en contra pudiera explicar el voto en contra. Porque posiblemente otros lectores tengan la misma idea errónea (sea la que sea), y luego podríamos aclarar eso. Todos se beneficiarían, en lugar de que algunos fueran engañados. Entonces, por favor explique su voto negativo. Gracias.
Saludos y hth. - Alf
68

Para resumir la publicación anterior de Cheers y hth. - Alf, asegúrate de tener main()o WinMain()definido y g ++ debería hacer lo correcto.

Mi problema fue que main()se definió dentro de un espacio de nombres por accidente.

Tim Ludwinski
fuente
Me acabo de dar cuenta de algo importante sobre todo esto. En mi caso, no encontró main () ya que no declaré ningún argumento (argc, argv). Una vez agregado, encontró main. Además, la naturaleza de cómo funciona esto significa que mingw está tratando de ayudar proporcionando su propio main que a su vez llama a WinMain. Los programas GUI solo tendrían WinMain y el stub principal en mingw se usa para llegar allí. Si tiene un main, entonces lo usa en su lugar.
Jeff Muir
extern "C" int main (void) solucionó el problema para mí
Dryler
33

Me encontré con este error al compilar mi aplicación con SDL. Esto se debió a que SDL definió su propia función principal en SDL_main.h. Para evitar que SDL defina la función principal, se debe definir una macro SDL_MAIN_HANDLED antes de que se incluya el encabezado SDL.h.

X-Frox
fuente
¡Gran respuesta! +1
Mohammad Kanan
¡Muchas gracias! Este comando funciona: 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 de
5

Intente guardar su archivo .c antes de compilar. Creo que su computadora está haciendo referencia a una ruta a un archivo sin información dentro de él.

- Tuve un problema similar al construir proyectos C

JabbaJava
fuente
Esto realmente resolvió mi problema, y ​​dejo este comentario para ayudarlo a obtener más atención.
David Chen
0

Compruebe que todos los archivos estén incluidos en su proyecto:

Tuve este mismo error emergente después de actualizar cLion. Después de horas de retoques, noté que uno de mis archivos no estaba incluido en el objetivo del proyecto. Después de agregarlo de nuevo al proyecto activo, dejé de obtener la referencia indefinida a winmain16 y el código se compiló.

Editar: también vale la pena verificar la configuración de compilación dentro de su IDE.

(No estoy seguro de si este error está relacionado con la actualización reciente del IDE; podría ser causal o simplemente correlativo. ¡No dude en comentar cualquier información sobre ese factor!)


fuente