authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-15 19:39:44-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-15 19:39:44-07:00
log996a2284dde16b030a63cb9ba42f586c7a1b66cd
treee081338028a98565fc44bd77c45bf90a3e1d862e
parent51a3d0603c116d99c0a93dd451a69c79dd0cbca2
parentd87bd3d8afc883853958389fcf4c65826426769b

Merge branch 'AnthonyYoManz-5002-fix-entrypoint-with-winmain'

closes #5002 closes #5613

4 files changed, 49 insertions(+), 22 deletions(-)

lib/std/os/windows/kernel32.zig+1-2
......@@ -84,6 +84,7 @@ pub extern "kernel32" fn FormatMessageW(dwFlags: DWORD, lpSource: ?LPVOID, dwMes
8484pub extern "kernel32" fn FreeEnvironmentStringsW(penv: [*:0]u16) callconv(.Stdcall) BOOL;
8585
8686pub extern "kernel32" fn GetCommandLineA() callconv(.Stdcall) LPSTR;
87pub extern "kernel32" fn GetCommandLineW() callconv(.Stdcall) LPWSTR;
8788
8889pub extern "kernel32" fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) callconv(.Stdcall) BOOL;
8990
......@@ -111,8 +112,6 @@ pub extern "kernel32" fn GetFileAttributesW(lpFileName: [*]const WCHAR) callconv
111112
112113pub extern "kernel32" fn GetModuleFileNameW(hModule: ?HMODULE, lpFilename: [*]u16, nSize: DWORD) callconv(.Stdcall) DWORD;
113114
114pub extern "kernel32" fn GetModuleHandleA(lpModuleName: ?LPCSTR) callconv(.Stdcall) ?HMODULE;
115
116115pub extern "kernel32" fn GetModuleHandleW(lpModuleName: ?[*:0]const WCHAR) callconv(.Stdcall) ?HMODULE;
117116
118117pub extern "kernel32" fn GetLastError() callconv(.Stdcall) Win32Error;
lib/std/start.zig+41-9
......@@ -29,7 +29,15 @@ comptime {
2929 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
3030 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
3131 {
32 @export(WinMainCRTStartup, .{ .name = "WinMainCRTStartup" });
32 @export(WinStartup, .{ .name = "wWinMainCRTStartup" });
33 } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
34 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
35 {
36 @compileError("WinMain not supported; declare wWinMain or main instead");
37 } else if (@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup") and
38 !@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup"))
39 {
40 @export(wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" });
3341 }
3442 } else if (builtin.os.tag == .uefi) {
3543 if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" });
......@@ -143,7 +151,18 @@ fn _start() callconv(.Naked) noreturn {
143151 @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
144152}
145153
146fn WinMainCRTStartup() callconv(.Stdcall) noreturn {
154fn WinStartup() callconv(.Stdcall) noreturn {
155 @setAlignStack(16);
156 if (!builtin.single_threaded) {
157 _ = @import("start_windows_tls.zig");
158 }
159
160 std.debug.maybeEnableSegfaultHandler();
161
162 std.os.windows.kernel32.ExitProcess(initEventLoopAndCallMain(u8, callMain));
163}
164
165fn wWinMainCRTStartup() callconv(.Stdcall) noreturn {
147166 @setAlignStack(16);
148167 if (!builtin.single_threaded) {
149168 _ = @import("start_windows_tls.zig");
......@@ -151,7 +170,8 @@ fn WinMainCRTStartup() callconv(.Stdcall) noreturn {
151170
152171 std.debug.maybeEnableSegfaultHandler();
153172
154 std.os.windows.kernel32.ExitProcess(initEventLoopAndCallMain());
173 const result = initEventLoopAndCallMain(std.os.windows.INT, call_wWinMain);
174 std.os.windows.kernel32.ExitProcess(@bitCast(std.os.windows.UINT, result));
155175}
156176
157177// TODO https://github.com/ziglang/zig/issues/265
......@@ -205,7 +225,7 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 {
205225
206226 std.debug.maybeEnableSegfaultHandler();
207227
208 return initEventLoopAndCallMain();
228 return initEventLoopAndCallMain(u8, callMain);
209229}
210230
211231fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C) i32 {
......@@ -220,7 +240,7 @@ const bad_main_ret = "expected return type of main to be 'void', '!void', 'noret
220240
221241// This is marked inline because for some reason LLVM in release mode fails to inline it,
222242// and we want fewer call frames in stack traces.
223inline fn initEventLoopAndCallMain() u8 {
243inline fn initEventLoopAndCallMain(comptime Out: type, comptime mainFunc: fn () Out) Out {
224244 if (std.event.Loop.instance) |loop| {
225245 if (!@hasDecl(root, "event_loop")) {
226246 loop.init() catch |err| {
......@@ -234,7 +254,7 @@ inline fn initEventLoopAndCallMain() u8 {
234254
235255 var result: u8 = undefined;
236256 var frame: @Frame(callMainAsync) = undefined;
237 _ = @asyncCall(&frame, &result, callMainAsync, .{loop});
257 _ = @asyncCall(&frame, &result, callMainAsync, .{ u8, mainFunc, loop });
238258 loop.run();
239259 return result;
240260 }
......@@ -242,13 +262,13 @@ inline fn initEventLoopAndCallMain() u8 {
242262
243263 // This is marked inline because for some reason LLVM in release mode fails to inline it,
244264 // and we want fewer call frames in stack traces.
245 return @call(.{ .modifier = .always_inline }, callMain, .{});
265 return @call(.{ .modifier = .always_inline }, mainFunc, .{});
246266}
247fn callMainAsync(loop: *std.event.Loop) callconv(.Async) u8 {
267fn callMainAsync(comptime Out: type, comptime mainProc: fn () Out, loop: *std.event.Loop) callconv(.Async) Out {
248268 // This prevents the event loop from terminating at least until main() has returned.
249269 loop.beginOneEvent();
250270 defer loop.finishOneEvent();
251 return callMain();
271 return mainProc();
252272}
253273
254274// This is not marked inline because it is called with @asyncCall when
......@@ -290,3 +310,15 @@ pub fn callMain() u8 {
290310 else => @compileError(bad_main_ret),
291311 }
292312}
313
314pub fn call_wWinMain() std.os.windows.INT {
315 const hInstance = @ptrCast(std.os.windows.HINSTANCE, std.os.windows.kernel32.GetModuleHandleW(null).?);
316 const hPrevInstance: ?std.os.windows.HINSTANCE = null; // MSDN: "This parameter is always NULL"
317 const lpCmdLine = std.os.windows.kernel32.GetCommandLineW();
318
319 // There's no (documented) way to get the nCmdShow parameter, so we're
320 // using this fairly standard default.
321 const nCmdShow = std.os.windows.user32.SW_SHOW;
322
323 return root.wWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
324}
src/link/Coff.zig+4-8
......@@ -1097,17 +1097,13 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
10971097 try argv.append("-NODEFAULTLIB");
10981098 if (!is_lib) {
10991099 if (self.base.options.module) |module| {
1100 if (module.stage1_flags.have_winmain) {
1101 try argv.append("-ENTRY:WinMain");
1102 } else if (module.stage1_flags.have_wwinmain) {
1103 try argv.append("-ENTRY:wWinMain");
1104 } else if (module.stage1_flags.have_wwinmain_crt_startup) {
1105 try argv.append("-ENTRY:wWinMainCRTStartup");
1106 } else {
1100 if (module.stage1_flags.have_winmain_crt_startup) {
11071101 try argv.append("-ENTRY:WinMainCRTStartup");
1102 } else {
1103 try argv.append("-ENTRY:wWinMainCRTStartup");
11081104 }
11091105 } else {
1110 try argv.append("-ENTRY:WinMainCRTStartup");
1106 try argv.append("-ENTRY:wWinMainCRTStartup");
11111107 }
11121108 }
11131109 }
test/stack_traces.zig+3-3
......@@ -282,10 +282,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
282282 \\source.zig:10:8: [address] in main (test)
283283 \\ foo();
284284 \\ ^
285 \\start.zig:269:29: [address] in std.start.posixCallMainAndExit (test)
285 \\start.zig:289:29: [address] in std.start.posixCallMainAndExit (test)
286286 \\ return root.main();
287287 \\ ^
288 \\start.zig:143:5: [address] in std.start._start (test)
288 \\start.zig:151:5: [address] in std.start._start (test)
289289 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
290290 \\ ^
291291 \\
......@@ -294,7 +294,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
294294 switch (std.Target.current.cpu.arch) {
295295 .aarch64 => "", // TODO disabled; results in segfault
296296 else =>
297 \\start.zig:143:5: [address] in std.start._start (test)
297 \\start.zig:151:5: [address] in std.start._start (test)
298298 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
299299 \\ ^
300300 \\