Skip to content

Zig doesn't detect wWinMain symbol in C files. #18621

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
eLeCtrOssSnake opened this issue Jan 20, 2024 · 21 comments · Fixed by #19399
Closed

Zig doesn't detect wWinMain symbol in C files. #18621

eLeCtrOssSnake opened this issue Jan 20, 2024 · 21 comments · Fixed by #19399
Labels
bug Observed behavior contradicts documented or intended behavior os-windows regression It worked in a previous version of Zig, but stopped working.
Milestone

Comments

@eLeCtrOssSnake
Copy link

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.

@eLeCtrOssSnake eLeCtrOssSnake added the bug Observed behavior contradicts documented or intended behavior label Jan 20, 2024
@expikr
Copy link
Contributor

expikr commented Jan 20, 2024

@squeek502 related to #17763 ?

@squeek502
Copy link
Collaborator

@expikr, no, shouldn't be. My guess is #16109 or #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.

@squeek502 squeek502 added os-windows regression It worked in a previous version of Zig, but stopped working. labels Jan 20, 2024
@squeek502
Copy link
Collaborator

squeek502 commented Jan 20, 2024

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 #16109, but still need to confirm that.

@squeek502
Copy link
Collaborator

squeek502 commented Jan 20, 2024

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;
}

@Paul-Dempsey
Copy link

You didn't #define UNICODE before including windows.h

@squeek502
Copy link
Collaborator

squeek502 commented Jan 20, 2024

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)

@Paul-Dempsey
Copy link

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.

@squeek502
Copy link
Collaborator

squeek502 commented Jan 20, 2024

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

@andrewrk
Copy link
Member

andrewrk commented Mar 12, 2024

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?

@andrewrk andrewrk added this to the 0.12.0 milestone Mar 12, 2024
@squeek502
Copy link
Collaborator

squeek502 commented Mar 12, 2024

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.

@squeek502
Copy link
Collaborator

squeek502 commented Mar 22, 2024

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.

@ypsvlq
Copy link
Contributor

ypsvlq commented Mar 22, 2024

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.

@chawyehsu
Copy link

chawyehsu commented Mar 26, 2024

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;
}

@RossComputerGuy
Copy link
Contributor

@chawyehsu WinMain and wmain are two different things.

@chawyehsu
Copy link

@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.

@squeek502
Copy link
Collaborator

squeek502 commented Mar 26, 2024

See #19399 (comment): 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.

@andrewrk andrewrk modified the milestones: 0.13.0, 0.12.0 Mar 28, 2024
@juliannoble
Copy link
Contributor

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.

@squeek502
Copy link
Collaborator

squeek502 commented Apr 19, 2024

@juliannoble What main function are you expecting the compiler to use? See #19399 (comment) 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.

@juliannoble
Copy link
Contributor

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.

@squeek502
Copy link
Collaborator

squeek502 commented Apr 19, 2024

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.

@mrexodia
Copy link

I ran into this error while using zig c++ -target x86_64-windows-gnu main.cpp -o main.exe. The error was:

lld-link: error: undefined symbol: WinMain
>>> referenced by /workspaces/zig-linux-aarch64-0.13.0/lib/libc/mingw/crt/crtexewin.c:67
>>>               mingw32.lib(crtexewin.obj):(main)

The reason was that main was missing from my main.cpp file. Adding a int main() {} fixed the linker error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior os-windows regression It worked in a previous version of Zig, but stopped working.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants