referência indefinida a `WinMain @ 16 '

110

Quando tento construir um programa usando Eclipse CDT, obtenho o seguinte:

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

Por que é que? E como posso resolver esse problema?

Simplicidade
fonte

Respostas:

184

Considere o seguinte programa de nível de API do Windows:

#define NOMINMAX
#include <windows.h>

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

Agora vamos construí-lo usando o conjunto de ferramentas GNU (ou seja, g ++), sem opções especiais. Aqui gnucestá apenas um arquivo em lote que utilizo para isso. Ele apenas fornece opções para tornar o g ++ mais padrão:

C: \ test> gnuc x.cpp

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

C: \ test> _

Isso significa que o vinculador, por padrão, produziu um executável do subsistema do console . O valor do subsistema no cabeçalho do arquivo informa ao Windows quais serviços o programa requer. Neste caso, com o sistema de console, o programa requer uma janela de console.

Isso também faz com que o interpretador de comandos aguarde a conclusão do programa.

Agora vamos construí-lo com o subsistema GUI , o que significa apenas que o programa não requer uma janela de console:

C: \ test> gnuc x.cpp -mwindows

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

C: \ test> _

Espero que esteja tudo bem até agora, embora a -mwindowsbandeira esteja apenas semi-documentada.

Construir sem esse sinalizador semidocumentado, seria necessário informar mais especificamente ao vinculador qual valor de subsistema se deseja, e algumas bibliotecas de importação de API do Windows, em geral, terão que ser especificadas explicitamente:

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

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

C: \ test> _

Isso funcionou bem, com o conjunto de ferramentas GNU.

Mas e quanto ao conjunto de ferramentas da Microsoft, ou seja, Visual C ++?

Bem, construir como um executável de subsistema de console funciona bem:

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

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

C: \ test> _

No entanto, com a construção do conjunto de ferramentas da Microsoft como um subsistema GUI não funciona por padrão:

C: \ test> msvc x.cpp user32.lib / link / subsistema: windows
x.cpp
LIBCMT.lib (wincrt0.obj): erro LNK2019: símbolo externo não resolvido _WinMain @ 16 referenciado na função ___tmainCRTStartu
p
x.exe: erro fatal LNK1120: 1 externos não resolvidos

C: \ test> _

Tecnicamente, isso ocorre porque o vinculador da Microsoft não é padrão por padrão para o subsistema GUI . Por padrão, quando o subsistema é GUI, o vinculador da Microsoft usa um ponto de entrada da biblioteca de tempo de execução , a função onde a execução do código de máquina começa, chamada winMainCRTStartup, que chama o não padrão da Microsoft em WinMainvez do padrão main.

Não é grande coisa consertar isso.

Tudo o que você precisa fazer é informar ao vinculador da Microsoft qual ponto de entrada usar, ou seja mainCRTStartup, qual chama padrão main:

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

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

C: \ test> _

Sem problemas, mas muito tedioso. E tão misterioso e oculto que a maioria dos programadores do Windows, que em sua maioria usam apenas as ferramentas não padronizadas da Microsoft por padrão, nem mesmo sabem sobre isso, e pensam erroneamente que um programa de subsistema da GUI do Windows “deve” ter não padrão em WinMainvez de padrão main. De passagem, com C ++ 0x a Microsoft terá um problema com isso, já que o compilador deve anunciar se é independente ou hospedado (quando hospedado, deve suportar o padrão main).

De qualquer forma, essa é a razão pela qual g ++ pode reclamar da WinMainfalta: é uma função de inicialização não padrão boba que as ferramentas da Microsoft requerem por padrão para programas de subsistema GUI.

Mas, como você pode ver acima, o g ++ não tem problemas com o padrão, mainmesmo para um programa de subsistema de GUI.

Então qual poderia ser o problema?

Bem, provavelmente está faltando um main. E provavelmente você também não tem (adequado) WinMain! E então o g ++, depois de ter pesquisado main(não existe) e o não padrão da Microsoft WinMain(não existe), informa que o último está faltando.

Testando com uma fonte vazia:

C: \ test> digite nul> y.cpp

C: \ test> gnuc y.cpp -mwindows
c: / arquivos de programa / mingw / bin /../ lib / gcc / mingw32 / 4.4.1 /../../../ libmingw32.a (main.o): main.c :(. text + 0xd2 ): referência indefinida
ce para `WinMain @ 16 '
collect2: ld retornou 1 status de saída

C: \ test> _
Saúde e hth. - Alf
fonte
3
@Alf P. Steinbach. Muito obrigado pela sua boa resposta. Quanto a All you have to do is to tell Microsoft's linker which entry point to use, namely mainCRTStartup, which calls standard main. Existe uma maneira de fazer isso Eclipse CDTporque não estou usando a linha de comando. Obrigado
Simplicidade,
1
@ user588855: já que você está usando g ++, isso (provavelmente) não se aplica a você. Apenas a parte no final (provavelmente) se aplica. Ou seja, defina a mainou a WinMain, ou certifique-se de que o arquivo relevante esteja incluído no projeto. Saúde,
Saúde e hth. - Alf
@Alf P. Steinbach. O que você quer dizer com definir mainou winmain? Obrigado
Simplicity,
1
Acabei de criar um arquivo chamado main.cpp que tinha o código: int main () {}
De fato
3
Eu seria bom se cada downvoter pudesse explicar o downvote. Pois possivelmente outros leitores tenham o mesmo equívoco (seja ele qual for), e então poderíamos esclarecer isso. Todos se beneficiariam, em vez de alguns serem enganados. Então, por favor, explique seu voto negativo. Obrigado.
Saúde e hth. - Alf
68

Para resumir a postagem acima de Cheers e hth. - Alf, certifique-se de ter main()ou WinMain()definido e g ++ deve fazer a coisa certa.

Meu problema é que main()foi definido dentro de um namespace por acidente.

Tim Ludwinski
fonte
Acabei de perceber algo importante sobre tudo isso. No meu caso, ele não estava encontrando main (), pois não declarei nenhum argumento (argc, argv). Uma vez adicionado, encontrou o principal. Além disso, a natureza de como isso funciona significa que o mingw está tentando ajudar fornecendo seu próprio principal que, por sua vez, chama WinMain. Os programas GUI teriam apenas WinMain e o stub principal do mingw é usado para chegar lá. Se você tiver um principal, ele o usará.
Jeff Muir
extern "C" int main (void) corrigiu o problema para mim
dryler de
33

Eu estava encontrando esse erro ao compilar meu aplicativo com SDL. Isso foi causado por SDL definir sua própria função principal em SDL_main.h. Para evitar que SDL defina a função principal, uma macro SDL_MAIN_HANDLED deve ser definida antes que o cabeçalho SDL.h seja incluído.

X-Frox
fonte
Ótima resposta! +1
Mohammad Kanan
Muito obrigado! 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
8Observer 8 de
5

Tente salvar seu arquivo .c antes de criar. Acredito que seu computador esteja fazendo referência a um caminho para um arquivo sem nenhuma informação dentro dele.

--Teve um problema semelhante ao construir projetos C

JabbaJava
fonte
Isso realmente resolveu meu problema e estou deixando este comentário para ajudá-lo a receber mais atenção.
David Chen
0

Verifique se todos os arquivos estão incluídos em seu projeto:

Eu tive esse mesmo erro após atualizar o cLion. Após horas de ajustes, percebi que um dos meus arquivos não estava incluído no destino do projeto. Depois de adicioná-lo de volta ao projeto ativo, parei de obter a referência indefinida para winmain16 e o ​​código foi compilado.

Editar: também vale a pena verificar as configurações de construção em seu IDE.

(Não tenho certeza se esse erro está relacionado à atualização recente do IDE - pode ser causal ou simplesmente correlativo. Sinta-se à vontade para comentar com qualquer ideia sobre esse fator!)


fonte