2011-03-10 26 views
89

Cuando trato de crear un programa con Eclipse CDT, me sale el siguiente:referencia indefinida a `WinMain @ 16'

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

¿Por qué es eso? Y, ¿cómo puedo resolver este problema?

Respuesta

158

Considere el siguiente programa a nivel de API de Windows:

#define NOMINMAX 
#include <windows.h> 

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

Ahora vamos a construir usando herramientas GNU (es decir, g ++), no hay opciones especiales. Aquí gnuc es solo un archivo por lotes que uso para eso. Sólo se suministra opciones para hacer g ++ más estándar:

 
C:\test> gnuc x.cpp 

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

C:\test> _ 

Esto significa que el enlazador de manera predeterminada produjo un subsistema de la consola ejecutable. El valor del subsistema en el encabezado del archivo indica a Windows qué servicios requiere el programa. En este caso, con el 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 vamos a construir con subsistema de interfaz gráfica de usuario, que simplemente significa que el programa no requiere una ventana de la consola:

 
C:\test> gnuc x.cpp -mwindows 

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

C:\test> _ 

Con suerte eso está bien hasta ahora, aunque la bandera -mwindows es sólo semi-documentado.

edificio sin que la bandera semi-documentado uno tendría que decir más específicamente el enlazador que el valor subsistema que uno desea, y algunas bibliotecas de importación API de Windows entonces en general se tienen que especificar de forma explícita:

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

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

C:\test> _ 

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

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

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

 
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> _ 

Sin embargo, con la construcción de la cadena de herramientas de Microsoft como subsistema de interfaz gráfica de usuario no funciona por defecto:

 
C:\test> msvc x.cpp user32.lib /link /subsystem:windows 
x.cpp 
LIBCMT.lib(wincrt0.obj) : error LNK2019: unresolved external symbol [email protected] referenced in function ___tmainCRTStartu 
p 
x.exe : fatal error LNK1120: 1 unresolved externals 

C:\test> _ 

Técnicamente esto se debe a que Microsoft ’ s El vinculador no es estándar por defecto para el subsistema GUI. Por defecto, cuando el subsistema de interfaz gráfica de usuario es, entonces enlazador de Microsoft utiliza una biblioteca de tiempo de ejecución punto de entrada, la función donde se inicia la ejecución de código máquina, llamada winMainCRTStartup, que llama a Microsoft de no estándar WinMain en lugar de la norma main.

No hay problema para arreglar eso, sin embargo.

Todo lo que tiene que hacer es decirle enlazador de Microsoft, que el punto de entrada a utilizar, es decir mainCRTStartup, que llama norma 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> _ 

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 de Microsoft ’, ni siquiera lo conocen, y piensan erróneamente que un programa del subsistema GUI de Windows “ debe ” tener WinMain no estándar en lugar del estándar main. De paso, con C++ 0x, Microsoft tendrá un problema con esto, ya que el compilador debe entonces publicitar si es independiente o está alojado (cuando está alojado debe ser compatible con el estándar main).

De todos modos, esa es la razón por g ++ puede se quejan de falta WinMain: es una función de arranque no estándar tonta que las herramientas de Microsoft requieren por defecto para los programas de interfaz gráfica de usuario del subsistema.

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

¿Cuál podría ser el problema?

Bien, usted es probablemente que falta a main. ¡Y usted probablemente no tiene (propiamente) WinMain tampoco! Y luego g ++, después de haber buscado main (no existe), y para el no estándar WinMain de Microsoft (no existe), informa que falta este último.

Testing con una fuente de vacío:

 
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:(.text+0xd2): undefined referen 
ce to `[email protected]' 
collect2: ld returned 1 exit status 

C:\test> _ 
+2

@Alf P. Steinbach. Muchas gracias por su agradable respuesta. En cuanto a 'Todo lo que tienes que hacer es decirle al enlazador de Microsoft qué punto de entrada usar, es decir, mainCRTStartup, que llama a main main'. ¿Hay alguna manera de hacer eso? Eclipse CDT' ya que no estoy usando la línea de comando. Gracias – Simplicity

+1

@ user588855: ya que está usando g ++ que (probablemente) no se aplica a usted. Solo se aplica la parte al final (probablemente). Es decir, defina un 'main' o un' WinMain', o bien, asegúrese de que el archivo relevante esté incluido en el proyecto. Cheers, –

+0

@Alf P. Steinbach. ¿A qué te refieres con definir 'main' o' winmain'? Gracias – Simplicity

50

Para resumir el post anterior por Saludos y hth. - Alf, asegúrate de tener main() o WinMain() definidos y g ++ debería hacer lo correcto.

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

+0

Acabo de darme cuenta de algo importante sobre todo esto. En mi caso, no estaba encontrando main() ya que no declaraba 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 WinMain. Los programas de interfaz gráfica de usuario solo tendrían WinMain y el tope principal en mingw se usa para llegar allí. Si tiene un main, entonces usa eso en su lugar. –

15

Me encontré con este error al compilar mi aplicación con SDL. Esto fue causado por SDL definiendo su propia función principal en SDL_main.h. Para evitar SDL, defina la función principal que debe definirse una macro SDL_MAIN_HANDLED antes de incluir el encabezado SDL.h.

1

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.

--Tengo un problema similar al crear proyectos C