неопределенная ссылка на `WinMain @ 16 '

110

Когда я пытаюсь создать программу с использованием Eclipse CDT, я получаю следующее:

/mingw/lib/libmingw32.a(main.o):main.c:(.text+0x106): неопределенная ссылка на `WinMain @ 16

Это почему? И как я могу решить эту проблему?

Простота
источник

Ответы:

184

Рассмотрим следующую программу уровня Windows API:

#define NOMINMAX
#include <windows.h>

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

Теперь давайте создадим его, используя набор инструментов GNU (например, g ++), без специальных опций. Вот gnucтолько командный файл, который я использую для этого. Он предоставляет только параметры, чтобы сделать g ++ более стандартным:

C: \ тест> gnuc x.cpp

C: \ test> objdump -x a.exe | findstr / i "^ подсистема"
Подсистема 00000003 (Windows CUI)

C: \ тест> _

Это означает, что компоновщик по умолчанию создал исполняемый файл подсистемы консоли . Значение подсистемы в заголовке файла сообщает Windows, какие службы требуются программе. В этом случае с консольной системой программе требуется окно консоли.

Это также заставляет интерпретатор команд ждать завершения программы.

Теперь давайте создадим его с помощью подсистемы GUI , что просто означает, что программе не требуется окно консоли:

C: \ test> gnuc x.cpp -mwindows

C: \ test> objdump -x a.exe | findstr / i "^ подсистема"
Подсистема 00000002 (Windows GUI)

C: \ тест> _

Надеюсь, что пока все в порядке, хотя -mwindowsфлаг частично задокументирован.

При сборке без этого полудокументированного флага нужно было бы более конкретно указать компоновщику, какое значение подсистемы нужно, и некоторые библиотеки импорта Windows API, как правило, должны быть явно указаны:

C: \ test> gnuc x.cpp -Wl, -подсистема, окна

C: \ test> objdump -x a.exe | findstr / i "^ подсистема"
Подсистема 00000002 (Windows GUI)

C: \ тест> _

Это нормально работало с набором инструментов GNU.

Но как насчет набора инструментов Microsoft, то есть Visual C ++?

Что ж, сборка в качестве исполняемого файла консольной подсистемы работает нормально:

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

C: \ test> dumpbin / заголовки x.exe | find / i "подсистема" | find / i "Windows"
               3 подсистема (Windows CUI)

C: \ тест> _

Однако с построением инструментальной цепочки Microsoft в качестве подсистемы графического интерфейса пользователя по умолчанию не работает:

C: \ test> msvc x.cpp user32.lib / ссылка / подсистема: окна
x.cpp
LIBCMT.lib (wincrt0.obj): ошибка LNK2019: неразрешенный внешний символ _WinMain @ 16, указанный в функции ___tmainCRTStartu
п
x.exe: фатальная ошибка LNK1120: 1 неразрешенные внешние

C: \ тест> _

Технически это связано с тем, что компоновщик Microsoft по умолчанию нестандартен для подсистемы графического интерфейса . По умолчанию, когда подсистема является графическим пользовательским интерфейсом, компоновщик Microsoft использует точку входа в библиотеку времени выполнения, вызываемую функцию, с которой запускается выполнение машинного кода winMainCRTStartup, которая вызывает нестандартную функцию Microsoft WinMainвместо стандартной main.

Хотя нет ничего страшного в том, чтобы это исправить.

Все, что вам нужно сделать, это указать компоновщику Microsoft, какую точку входа использовать, а именно mainCRTStartup, которая вызывает стандарт main:

C: \ test> msvc x.cpp user32.lib / ссылка / подсистема: окна / запись: mainCRTStartup
x.cpp

C: \ test> dumpbin / заголовки x.exe | find / i "подсистема" | find / i "Windows"
               2 подсистема (графический интерфейс Windows)

C: \ тест> _

Нет проблем, но очень утомительно. И так загадочно и скрыто, что большинство программистов Windows, которые в основном используют только нестандартные инструменты Microsoft по умолчанию, даже не знают об этом и ошибочно думают, что программа подсистемы графического интерфейса Windows «должна» иметь нестандартные, WinMainа не стандартные. main. Между прочим, с C ++ 0x у Microsoft возникнут проблемы с этим, поскольку компилятор должен затем рекламировать, является ли он автономным или размещенным (при размещении он должен поддерживать стандарт main).

В любом случае, это причина, по которой g ++ может жаловаться на WinMainотсутствие: это глупая нестандартная функция запуска, которую инструменты Microsoft требуют по умолчанию для программ подсистемы графического интерфейса.

Но, как вы можете видеть выше, g ++ не имеет проблем со стандартом mainдаже для программы подсистемы GUI.

Так в чем может быть проблема?

Ну, вы, вероятно , не хватаетmain . И у вас, наверное, тоже нет (собственно) WinMain! А затем g ++ после поиска main(такого нет) и нестандартного от Microsoft WinMain(такого нет) сообщает, что последний отсутствует.

Тестирование с пустым источником:

C: \ test> введите nul> y.cpp

C: \ test> gnuc y.cpp -mwindows
c: / программные файлы / mingw / bin /../ lib / gcc / mingw32 / 4.4.1 /../../../ libmingw32.a (main.o): main.c :(. text + 0xd2 ): неопределенная ссылка
ce на `WinMain @ 16 '
collect2: ld вернул 1 статус выхода

C: \ тест> _
Приветствия и hth. - Альф
источник
3
@ Альф П. Штайнбах. Большое спасибо за хороший ответ. Что касается All you have to do is to tell Microsoft's linker which entry point to use, namely mainCRTStartup, which calls standard main. Есть ли способ сделать это, Eclipse CDTпоскольку я не использую командную строку. Спасибо
Simplicity
1
@ user588855: поскольку вы используете g ++, который (вероятно) к вам не относится. Применяется только часть в конце (вероятно). То есть определите a mainили a WinMain, или убедитесь, что соответствующий файл включен в проект. Приветствия,
Приветствия и hth. - Alf
@ Альф П. Штайнбах. Что вы имеете в виду под определением mainили winmain? Спасибо
Simplicity
1
Я только что создал файл с именем main.cpp с кодом: int main () {}
действительно,
3
Было бы хорошо, если бы каждый голосующий против мог объяснить свой голос. Возможно, у других читателей такое же заблуждение (каким бы оно ни было), и тогда мы могли бы это прояснить. Все выиграют, а не введут кого-то в заблуждение. Итак, пожалуйста, объясните свой голос против. Спасибо.
Приветствия и hth. - Alf
68

Подводя итог вышеупомянутому сообщению Cheers и hth. - Альф, убедитесь, что у вас есть main()или WinMain()определили и g ++ должен поступать правильно.

Моя проблема заключалась в том, что он main()был случайно определен внутри пространства имен.

Тим Людвински
источник
Только что понял кое-что важное во всем этом. В моем случае он не нашел main (), поскольку я не объявлял никаких аргументов (argc, argv). После добавления он обнаружил main. Кроме того, характер того, как это работает, означает, что mingw пытается помочь, предоставляя свой собственный main, который, в свою очередь, вызывает WinMain. Программы с графическим интерфейсом будут иметь только WinMain, и для этого используется основная заглушка в mingw. Если у вас есть main, он использует его.
Джефф Мьюир
extern "C" int main (void)
устранил
33

Я столкнулся с этой ошибкой при компиляции приложения с помощью SDL. Это было вызвано тем, что SDL определил свою основную функцию в SDL_main.h. Чтобы не допустить, чтобы SDL определяла основную функцию, макрос SDL_MAIN_HANDLED должен быть определен до включения заголовка SDL.h.

X-Frox
источник
Отличный ответ! +1
Мохаммад Канан
Большое спасибо! Эта команда работает: 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

Перед сборкой попробуйте сохранить файл .c. Я считаю, что ваш компьютер ссылается на путь к файлу, в котором нет никакой информации.

- Была аналогичная проблема при создании проектов C

JabbaJava
источник
Это фактически решило мою проблему, и я оставляю этот комментарий, чтобы привлечь к нему больше внимания.
Дэвид Чен
0

Убедитесь, что все файлы включены в ваш проект:

У меня была такая же ошибка после обновления cLion. После нескольких часов возня я заметил, что один из моих файлов не был включен в цель проекта. После того, как я добавил его обратно в активный проект, я перестал получать неопределенную ссылку на winmain16, и код компилировался.

Изменить: также стоит проверить настройки сборки в вашей среде IDE.

(Не уверен, связана ли эта ошибка с недавним обновлением IDE - может быть причинной или просто коррелятивной. Не стесняйтесь комментировать, какое-либо понимание этого фактора!)


источник