niezdefiniowane odniesienie do `WinMain @ 16 '

110

Kiedy próbuję zbudować program przy użyciu Eclipse CDT, otrzymuję:

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

Dlaczego? Jak mogę rozwiązać ten problem?

Prostota
źródło

Odpowiedzi:

184

Rozważmy następujący program na poziomie interfejsu API systemu Windows:

#define NOMINMAX
#include <windows.h>

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

Teraz zbudujmy go używając GNU toolchain (tj. G ++), bez specjalnych opcji. Oto gnuctylko plik wsadowy, którego używam do tego. Dostarcza tylko opcje zwiększające standard g ++:

C: \ test> gnuc x.cpp

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

C: \ test> _

Oznacza to, że konsolidator domyślnie utworzył plik wykonywalny podsystemu konsoli . Wartość podsystemu w nagłówku pliku mówi systemowi Windows, jakich usług wymaga program. W tym przypadku, z systemem konsoli, program wymaga okna konsoli.

Powoduje to również, że interpreter poleceń czeka na zakończenie programu.

Teraz zbudujmy go z podsystemem GUI , co oznacza po prostu, że program nie wymaga okna konsoli:

C: \ test> gnuc x.cpp -mwindows

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

C: \ test> _

Miejmy nadzieję, że jak dotąd jest to w porządku, chociaż -mwindowsflaga jest tylko częściowo udokumentowana.

Budując bez tej częściowo udokumentowanej flagi, należałoby dokładniej powiedzieć konsolidatorowi, jakiej wartości podsystemu chce, a niektóre biblioteki importu API systemu Windows będą musiały być ogólnie określone jawnie:

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

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

C: \ test> _

To działało dobrze z łańcuchem narzędzi GNU.

Ale co z łańcuchem narzędzi Microsoft, czyli Visual C ++?

Cóż, budowanie jako plik wykonywalny podsystemu konsoli działa dobrze:

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

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

C: \ test> _

Jednak z budowaniem łańcucha narzędzi firmy Microsoft jako podsystemu GUI nie działa domyślnie:

C: \ test> msvc x.cpp user32.lib / link / subsystem: windows
x.cpp
LIBCMT.lib (wincrt0.obj): błąd LNK2019: nierozwiązany symbol zewnętrzny _WinMain @ 16, do którego odwołuje się funkcja ___tmainCRTStartu
p
x.exe: błąd krytyczny LNK1120: 1 nierozwiązane zewnętrzne

C: \ test> _

Technicznie jest to spowodowane tym, że konsolidator Microsoftu jest domyślnie niestandardowy dla podsystemu GUI . Domyślnie, gdy podsystemem jest GUI, wówczas konsolidator Microsoftu używa punktu wejścia biblioteki środowiska wykonawczego , funkcji, w której rozpoczyna się wykonywanie kodu maszynowego, nazywanej winMainCRTStartup, która wywołuje niestandardowy WinMainzamiast standardowego Microsoft main.

Jednak nic wielkiego, żeby to naprawić.

Wszystko, co musisz zrobić, to powiedzieć linkerowi Microsoftu, którego punktu wejścia użyć, a mianowicie mainCRTStartup, który wywołuje standard main:

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

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

C: \ test> _

Żaden problem, ale bardzo uciążliwy. I tak tajemniczy i ukryty, że większość programistów Windows, którzy przeważnie używają tylko niestandardowych narzędzi Microsoftu, nawet o tym nie wie i błędnie myśli, że program podsystemu GUI Windows „musi” mieć niestandardowy WinMainzamiast standardowego main. Na marginesie, z C ++ 0x Microsoft będzie miał z tym problem, ponieważ kompilator musi następnie ogłosić, czy jest wolnostojący, czy hostowany (gdy jest hostowany, musi obsługiwać standard main).

W każdym razie, to jest powód, dla którego g ++ może narzekać, że WinMainbrakuje: jest to głupia niestandardowa funkcja startowa, której narzędzia Microsoftu wymagają domyślnie dla programów podsystemu GUI.

Ale jak widać powyżej, g ++ nie ma problemu ze standardem mainnawet dla programu podsystemu GUI.

Więc jaki może być problem?

Cóż, prawdopodobnie brakuje ci main. I prawdopodobnie nie masz też (właściwego) WinMain! A potem g ++, po wyszukaniu main(nie takiego) i niestandardowego Microsoft WinMain(nie takiego), zgłasza, że ​​brakuje tego ostatniego.

Testowanie z pustym źródłem:

C: \ test> wpisz 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 ): niezdefiniowane odwołanie
ce do `` WinMain @ 16 ''
collect2: ld zwrócił 1 status wyjścia

C: \ test> _
Pozdrawiam i hth. - Alf
źródło
3
@Alf P. Steinbach. Dziękuję bardzo za miłą odpowiedź. Co do All you have to do is to tell Microsoft's linker which entry point to use, namely mainCRTStartup, which calls standard main. Czy istnieje sposób, aby to zrobić, Eclipse CDTponieważ nie używam wiersza poleceń. Dzięki
Prostota
1
@ user588855: skoro używasz g ++, to (prawdopodobnie) Ciebie nie dotyczy. Obowiązuje tylko część na końcu (prawdopodobnie). Oznacza to, że zdefiniuj a mainlub a WinMain, lub upewnij się, że odpowiedni plik jest uwzględniony w projekcie. Pozdrawiam,
Pozdrawiam i hth. - Alf
@Alf P. Steinbach. Co masz na myśli, określając mainlub winmain? Dzięki
Prostota
1
Właśnie utworzyłem plik o nazwie main.cpp, który miał kod: int main () {}
rzeczywiście,
3
Byłoby miło, gdyby każdy przeciwnik mógł wyjaśnić swój głos przeciw. Być może inni czytelnicy mają to samo błędne przekonanie (cokolwiek to jest), a wtedy moglibyśmy to wyjaśnić. Wszyscy skorzystaliby na tym, zamiast dać się zwieść. Więc proszę, wyjaśnij swój głos przeciw. Dziękuję Ci.
Pozdrawiam i hth. - Alf
68

Podsumowując powyższy post przez Cheers i hth. - Alf, Upewnij się, że masz main()lub WinMain()zdefiniowałeś, a g ++ powinno zrobić właściwą rzecz.

Mój problem polegał na tym, że main()zostało to przypadkowo zdefiniowane w przestrzeni nazw.

Tim Ludwiński
źródło
Właśnie zdałem sobie sprawę z czegoś ważnego w tym wszystkim. W moim przypadku nie znajdowało to main (), ponieważ nie zadeklarowałem żadnych argumentów (argc, argv). Po dodaniu znalazł plik main. Ponadto charakter tego działania oznacza, że ​​mingw stara się pomóc, udostępniając swój własny plik main, który z kolei wywołuje WinMain. Programy GUI miałyby tylko WinMain, a do tego celu służy główny kod pośredniczący w mingw. Jeśli masz main, używa go zamiast tego.
Jeff Muir,
extern "C" int main (void) naprawił problem dla mnie
dryler
33

Wystąpił ten błąd podczas kompilowania mojej aplikacji z SDL. Było to spowodowane definiowaniem przez SDL swojej własnej głównej funkcji w SDL_main.h. Aby uniemożliwić SDL zdefiniowanie głównej funkcji, przed dołączeniem nagłówka SDL.h należy zdefiniować makro SDL_MAIN_HANDLED.

X-Frox
źródło
Świetna odpowiedź! +1
Mohammad Kanan
Wielkie dzięki! To polecenie działa: 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

Spróbuj zapisać plik .c przed rozpoczęciem budowania. Wydaje mi się, że Twój komputer odwołuje się do ścieżki do pliku, który nie zawiera żadnych informacji.

- Miałem podobny problem podczas tworzenia projektów C.

JabbaJava
źródło
To faktycznie rozwiązało mój problem i zostawiam ten komentarz, aby pomóc mu przyciągnąć więcej uwagi.
David Chen
0

Sprawdź, czy wszystkie pliki są zawarte w Twoim projekcie:

Ten sam błąd pojawił się po aktualizacji cLion. Po godzinach majsterkowania zauważyłem, że jeden z moich plików nie został uwzględniony w celu projektu. Po dodaniu go z powrotem do aktywnego projektu, przestałem pobierać niezdefiniowane odwołanie do winmain16 i skompilowałem kod.

Edycja: warto również sprawdzić ustawienia kompilacji w swoim IDE.

(Nie jestem pewien, czy ten błąd jest związany z niedawną aktualizacją IDE - może być przyczynowy lub po prostu skorelowany. Zapraszam do komentowania z wszelkimi spostrzeżeniami na temat tego czynnika!)


źródło