zig
zig copied to clipboard
Zig doesn't detect wWinMain symbol in C files.
Zig Version
0.12.0-dev.2159+7916cf6f8
Steps to Reproduce and Observed Behavior
Compile some C code that has a wWinMain startup point. (my use case: C application built by build.zig) Observe that compiler ignores wWinMain definition and instead complains about the absence of main.
Side notes: This issue is not present on the 0.11.0 version. Declaring main instead of wWinMain works. This is the current workaround that I am using. This is observed on both x86-windows and x86_64-windows
Zig build log: https://paste.sr.ht/~electrosssnake/da3a6d579b24d868d2f32f75f3c7b95b43686142 Whole build.zig: https://paste.sr.ht/~electrosssnake/ce4e6a9b7f184d910e2b309381da62ccf871b922 C file(start.c) that contains windows startup symbol: https://paste.sr.ht/~electrosssnake/8ac72ced13aed44f53549fe354baa9adeb068b56
Expected Behavior
Zig correctly detects wWinMain and builds the application.
@squeek502 related to https://github.com/ziglang/zig/pull/17763 ?
@expikr, no, shouldn't be. My guess is https://github.com/ziglang/zig/pull/16109 or https://github.com/ziglang/zig/pull/13514.
Would be good to get a minimal failing test case for this that can be added to the standalone tests once this is fixed.
Minimal test case:
// wwinmain.c
#include <windows.h>
int APIENTRY wWinMain(HINSTANCE hInst, HINSTANCE hInstPrev, PWSTR cmdline, int cmdshow) {
return 0;
}
Fails:
> zig build-exe wwinmain.c -lc
error: lld-link: undefined symbol: main
note: referenced by C:\Users\Ryan\Programming\Zig\zig\lib\libc\mingw\crt\crtexe.c:267
note: C:\Users\Ryan\AppData\Local\zig\o\01924fb85758874f67102f866bb06ff5\crt2.obj:(__tmainCRTStartup)
Targeting the MSVC ABI does work, so it's very likely MinGW related:
> zig build-exe wwinmain.c -lc -target native-windows-msvc
So probably caused by https://github.com/ziglang/zig/pull/16109, but still need to confirm that.
Hm, I can't actually get wWinMain to compile successfully with 0.11.0 either:
> "C:\Users\Ryan\Programming\Zig\zig-windows-x86_64-0.11.0\zig.exe" build-exe wwinmain.c -lc
error: lld-link: undefined symbol: WinMain
note: referenced by C:\Users\Ryan\Programming\Zig\zig-windows-x86_64-0.11.0\lib\libc\mingw\crt\crt0_c.c:18
note: mingw32.lib(crt0_c.obj):(main)
Using WinMain works with 0.11.0, though:
#include <windows.h>
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, PSTR cmdline, int cmdshow) {
return 0;
}
You didn't #define UNICODE before including windows.h
Tried that, didn't seem to change anything and isn't done in the OP reproduction.
EDIT: Also, wWinMain is detected and compiled as expected when targeting the MSVC ABI (without the need for #define UNICODE):
> zig build-exe wwinmain.c -lc -target native-windows-msvc
> dumpbin /headers wwinmain.exe
OPTIONAL HEADER VALUES
13B0 entry point (00000001400013B0) wWinMainCRTStartup
2 subsystem (Windows GUI)
In usual C windows app, wWinMain would be a "wide", meaning Unicode entry. For Unicode app, one #defines UNICODE or _UNICODE before including windows.h. (and pass the linker flag to indicate that the app is for the windows subsystem). Not sure what magic zig does for Wndows targets, though.
Unless I'm mistaken, I think any magic being done is performed by the linker. From the /ENTRY docs:
If the /DLL or /SUBSYSTEM option is not specified, the linker selects a subsystem and entry point depending on whether main or WinMain is defined.
In this case, /ENTRY is not being set explicitly, so it's up to the linker to figure out the entry and subsystem. In both the -gnu and -msvc case, Zig is using lld-link.
Here's the --verbose-link of the successful -msvc target (that finds wWinMain and identifies the subsystem as Windows, see the edit in my post above):
lld-link -ERRORLIMIT:0 -NOLOGO -DEBUG -PDB:wwinmain.pdb -PDBALTPATH:wwinmain.pdb -STACK:16777216 -BASE:4194304 -MACHINE:X64 -OUT:wwinmain.exe -IMPLIB:wwinmain.lib -LIBPATH:C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\ucrt\x64 -LIBPATH:C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.34.31933\Lib\x64 -LIBPATH:C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\um\x64 C:\Users\Ryan\Programming\Zig\tmp\zig-cache\o\46f93a70bc677800051255e7f42ea4d3\wwinmain.obj libcmtd.lib libvcruntimed.lib libucrtd.lib legacy_stdio_definitions.lib kernel32.lib ntdll.lib C:\Users\Ryan\AppData\Local\zig\o\8438dc6e9ec5db159875bf6f754de588\compiler_rt.lib
And here's the --verbose-link of the failing -gnu target (this is Zig master):
lld-link -ERRORLIMIT:0 -NOLOGO -DEBUG -PDB:wwinmain.pdb -PDBALTPATH:wwinmain.pdb -STACK:16777216 -BASE:4194304 -MACHINE:X64 -INCLUDE:_tls_index -OUT:wwinmain.exe -IMPLIB:wwinmain.lib C:\Users\Ryan\Programming\Zig\tmp\zig-cache\o\1499d7be033dc90abbc0973f6b59191b\wwinmain.obj -lldmingw -ALTERNATENAME:__image_base__=__ImageBase C:\Users\Ryan\AppData\Local\zig\o\847d3e8ad61a4ab9750e0d4aa9146dca\crt2.obj C:\Users\Ryan\AppData\Local\zig\o\f12e821dbfd38e42aae511e9654fca07\mingw32.lib C:\Users\Ryan\AppData\Local\zig\o\c2392418c63a5ab2a03a19960edd8e69\mingwex.lib C:\Users\Ryan\AppData\Local\zig\o\8edafe95963d1cd8b407527ac6593287\uuid.lib C:\Users\Ryan\AppData\Local\zig\o\56e5f3e56df86bc4014af1a379e6e042\compiler_rt.lib C:\Users\Ryan\AppData\Local\zig\o\505bc0d71ff1285b1eb0cc64da28c44e\ucrtbase.lib C:\Users\Ryan\AppData\Local\zig\o\ee182b5bddf3e9a2675745d8c5ffe60b\advapi32.lib C:\Users\Ryan\AppData\Local\zig\o\790905d8de4800ac8c29de90cdead242\kernel32.lib C:\Users\Ryan\AppData\Local\zig\o\40eecd0ec8726abb8504993aba165a94\ntdll.lib C:\Users\Ryan\AppData\Local\zig\o\223ffca71a434db4d4da5510f10ff21f\shell32.lib C:\Users\Ryan\AppData\Local\zig\o\1cab3585b4c499d173061b2f01cddd5b\user32.lib
And here's the --verbose-link when using 0.11.0 and targeting -gnu (which is also failing for me but was reported to succeed in the OP):
lld-link -ERRORLIMIT:0 -NOLOGO -DEBUG -PDB:wwinmain.pdb -PDBALTPATH:wwinmain.pdb -STACK:16777216 -MACHINE:X64 -INCLUDE:_tls_index -OUT:wwinmain.exe -IMPLIB:wwinmain.lib C:\Users\Ryan\AppData\Local\zig\o\d76861145d4e143b4af210cbdfbc3200\wwinmain.obj -lldmingw -ALTERNATENAME:__image_base__=__ImageBase C:\Users\Ryan\AppData\Local\zig\o\829949829aa7326dafc4f1f0f6d9c46a\crt2.obj C:\Users\Ryan\AppData\Local\zig\o\008204667472725c754aa94752e9e2b6\mingw32.lib C:\Users\Ryan\AppData\Local\zig\o\66b415c51e4aeb7de6d40842bf1b4203\mingwex.lib C:\Users\Ryan\AppData\Local\zig\o\a08a47ce6962154e04236f0d5b665be3\msvcrt-os.lib C:\Users\Ryan\AppData\Local\zig\o\c26457baea6286ace30a53be12ab2fcc\uuid.lib C:\Users\Ryan\AppData\Local\zig\o\f1972e2c1c4c97624e9cef0904e8a65e\ssp.lib C:\Users\Ryan\AppData\Local\zig\o\583f619fc83310fca4d63e7a8e3ee6db\compiler_rt.lib C:\Users\Ryan\AppData\Local\zig\o\7efad3ef36db57a1639f59ece7a3aa42\advapi32.lib C:\Users\Ryan\AppData\Local\zig\o\7611b689f99fc5b3e10b0b40738df706\kernel32.lib C:\Users\Ryan\AppData\Local\zig\o\7c21b883223120ff9d0540f5b993eb68\msvcrt.lib C:\Users\Ryan\AppData\Local\zig\o\b4823eabe65fcca4946c88b20391d579\ntdll.lib C:\Users\Ryan\AppData\Local\zig\o\bea7906fdb568e9bcad4265a9e219c2b\shell32.lib C:\Users\Ryan\AppData\Local\zig\o\c913a797e5913938baf70100f03b0aaf\user32.lib
Observe that compiler ignores wWinMain definition and instead complains about the absence of main.
Have you tried putting
pub const wWinMain = void;
in your root source file?
root source file
Note that this is a problem with compiling C files, not Zig files.
Minimal reproduction is
#include <windows.h>
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, PSTR cmdline, int cmdshow) {
return 0;
}
zig build-exe winmain.c -lc -target native-windows-gnu --subsystem windows
This worked in 0.11.0.
cc @ypsvlq on the off-chance you have some insight on this.
EDIT: This seems potentially relevant: https://sourceforge.net/p/mingw-w64/mailman/mingw-w64-public/thread/20221113114053.ze3h5pt4s7do53fi@pali/
but including crtexewin.c in crt2 doesn't seem to change the linker looking for the main symbol.
In msvc, the linker detects wWinMain/WinMain/wmain/main and chooses the appropriate startup code.
In mingw, unicode is enabled by the -municode switch and WinMain is called by a fallback implementation of (w)main, which is (u)crtexewin from libmingw32.a.
Currently Zig doesn't build crtexewin, but other changes might be needed, I'll look in more detail later.
I'm encoutering this using zig 0.11.0, and tested back on 0.10.0 this also appears. I don't think this was supported in zig and it should not be marked as regression?
$ zig version
0.11.0
$ zig c++ main.cpp
LLD Link... lld-link: error: undefined symbol: WinMain
>>> referenced by [...]\zig\current\lib\libc\mingw\crt\crt0_c.c:18
>>> mingw32.lib(crt0_c.obj):(main)
$ zig version
0.10.0
$ zig c++ main.cpp
LLD Link... lld-link: error: undefined symbol: WinMain
>>> referenced by mingw32.lib(crt0_c.obj):(main)
minimal repro
int wmain(int argc, wchar_t* argv[]) {
return 0;
}
@chawyehsu WinMain and wmain are two different things.
@RossComputerGuy Did I misunderstand here? I'm talking about the issue of unicode entry against mingw here. I know the difference between WinMain and wmain.
See https://github.com/ziglang/zig/pull/19399#issuecomment-2019420611: the regression is with regards to WinMain, and I think you're right that the unicode entry points have never been supported when targeting MinGW.
I'm getting similar with 0.12.0-dev.3674+a0de07760 Target also x86-windows-gnu Being driven from a zig.build which is a somewhat unwieldy translation of a (to me) complex Makefile as an attempt to build the commandline Tclsh shell. I supply -mconsole - but am unclear on where/how to try adding --subsystem arguments in this context.
error: lld-link: undefined symbol: WinMain note: referenced by C:\zig\lib\libc\mingw\crt\crtexewin.c:67 note: mingw32.lib(crtexewin.obj):(main) error: lld-link -ERRORLIMIT:0 -NOLOGO -DEBUG -PDB:C:\buildtcl\2024zig\build_tcl90\zig-cache\o\e62bac644c2625c5965792447010bbc5\tclsh.pdb -PDBALTPATH:tclsh.pdb -STACK:16777216 -BASE:4194304 -MACHINE:X64 -INCLUDE:_tls_index -OUT:C:\buildtcl\2024zig\build_tcl90\zig-cache\o\e62bac644c2625c5965792447010bbc5\tclsh.exe -IMPLIB:C:\buildtcl\2024zig\build_tcl90\zig-cache\o\e62bac644c2625c5965792447010bbc5\tclsh.lib ...
I note that a search of the zig-cache\o doesn't find the tclsh.pdb or tclsh.lib shown in the lld-link error line above - but I have generated dlls for this project where the .pdb files are output both in the zig-cache and zig-out.
@juliannoble What main function are you expecting the compiler to use? See https://github.com/ziglang/zig/pull/19399#issuecomment-2016527584 for what you need to pass to zig build-exe for each possible main function and see https://github.com/ziglang/zig/blob/master/test/standalone/windows_entry_points/build.zig for the build.zig equivalents.
Sorry, I don't know enough about entry points and specifically how tclsh works to answer. I am using -municode at the appropriate place I think - and also -DUNICODE and -D_UNICODE tclsh requires compiling tclMain.c twice - once with unicode. The object names are then tclMain.o and tclMainW.o I couldn't find any zig.build way to do this other than by making another copy of tclMain.c as tclMainW.c tclAppInit.c also requires unicode flags and has something to do with it. ( _tmain ) My apologies if it's not appropriate to mention here - but I'm willing to pay for assistance either directly and/or donation to zig project - I'm just not sure how much of this problem is specific to zig vs perhaps peculiarities in the way this project operates.
I think this is just a case of the error message being confusing. If I try to compile a completely empty C file (with no main function) I get the same error as you:
> zig build-exe empty.c -lc --subsystem console
error: lld-link: undefined symbol: WinMain
note: referenced by C:\Users\Ryan\Programming\Zig\zig\lib\libc\mingw\crt\crtexewin.c:67
note: mingw32.lib(crtexewin.obj):(main)
So what's likely happening is that you're trying to compile an executable but the linker is unable to find any suitable main symbol at all.
If so, this is unrelated to this issue (this issue is about wanting to use WinMain/wWinMain as your main function) and I'd suggest asking for help with your problem in one of the community spaces.