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...@@ -84,6 +84,7 @@ pub extern "kernel32" fn FormatMessageW(dwFlags: DWORD, lpSource: ?LPVOID, dwMes
84pub extern "kernel32" fn FreeEnvironmentStringsW(penv: [*:0]u16) callconv(.Stdcall) BOOL;84pub extern "kernel32" fn FreeEnvironmentStringsW(penv: [*:0]u16) callconv(.Stdcall) BOOL;
8585
86pub extern "kernel32" fn GetCommandLineA() callconv(.Stdcall) LPSTR;86pub extern "kernel32" fn GetCommandLineA() callconv(.Stdcall) LPSTR;
87pub extern "kernel32" fn GetCommandLineW() callconv(.Stdcall) LPWSTR;
8788
88pub extern "kernel32" fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) callconv(.Stdcall) BOOL;89pub 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...@@ -111,8 +112,6 @@ pub extern "kernel32" fn GetFileAttributesW(lpFileName: [*]const WCHAR) callconv
111112
112pub extern "kernel32" fn GetModuleFileNameW(hModule: ?HMODULE, lpFilename: [*]u16, nSize: DWORD) callconv(.Stdcall) DWORD;113pub 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
116pub extern "kernel32" fn GetModuleHandleW(lpModuleName: ?[*:0]const WCHAR) callconv(.Stdcall) ?HMODULE;115pub extern "kernel32" fn GetModuleHandleW(lpModuleName: ?[*:0]const WCHAR) callconv(.Stdcall) ?HMODULE;
117116
118pub extern "kernel32" fn GetLastError() callconv(.Stdcall) Win32Error;117pub extern "kernel32" fn GetLastError() callconv(.Stdcall) Win32Error;
lib/std/start.zig+41-9
...@@ -29,7 +29,15 @@ comptime {...@@ -29,7 +29,15 @@ comptime {
29 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and29 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
30 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))30 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
31 {31 {
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" });
33 }41 }
34 } else if (builtin.os.tag == .uefi) {42 } else if (builtin.os.tag == .uefi) {
35 if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" });43 if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" });
...@@ -143,7 +151,18 @@ fn _start() callconv(.Naked) noreturn {...@@ -143,7 +151,18 @@ fn _start() callconv(.Naked) noreturn {
143 @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});151 @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
144}152}
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 {
147 @setAlignStack(16);166 @setAlignStack(16);
148 if (!builtin.single_threaded) {167 if (!builtin.single_threaded) {
149 _ = @import("start_windows_tls.zig");168 _ = @import("start_windows_tls.zig");
...@@ -151,7 +170,8 @@ fn WinMainCRTStartup() callconv(.Stdcall) noreturn {...@@ -151,7 +170,8 @@ fn WinMainCRTStartup() callconv(.Stdcall) noreturn {
151170
152 std.debug.maybeEnableSegfaultHandler();171 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));
155}175}
156176
157// TODO https://github.com/ziglang/zig/issues/265177// TODO https://github.com/ziglang/zig/issues/265
...@@ -205,7 +225,7 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 {...@@ -205,7 +225,7 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 {
205225
206 std.debug.maybeEnableSegfaultHandler();226 std.debug.maybeEnableSegfaultHandler();
207227
208 return initEventLoopAndCallMain();228 return initEventLoopAndCallMain(u8, callMain);
209}229}
210230
211fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C) i32 {231fn 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...@@ -220,7 +240,7 @@ const bad_main_ret = "expected return type of main to be 'void', '!void', 'noret
220240
221// This is marked inline because for some reason LLVM in release mode fails to inline it,241// This is marked inline because for some reason LLVM in release mode fails to inline it,
222// and we want fewer call frames in stack traces.242// and we want fewer call frames in stack traces.
223inline fn initEventLoopAndCallMain() u8 {243inline fn initEventLoopAndCallMain(comptime Out: type, comptime mainFunc: fn () Out) Out {
224 if (std.event.Loop.instance) |loop| {244 if (std.event.Loop.instance) |loop| {
225 if (!@hasDecl(root, "event_loop")) {245 if (!@hasDecl(root, "event_loop")) {
226 loop.init() catch |err| {246 loop.init() catch |err| {
...@@ -234,7 +254,7 @@ inline fn initEventLoopAndCallMain() u8 {...@@ -234,7 +254,7 @@ inline fn initEventLoopAndCallMain() u8 {
234254
235 var result: u8 = undefined;255 var result: u8 = undefined;
236 var frame: @Frame(callMainAsync) = undefined;256 var frame: @Frame(callMainAsync) = undefined;
237 _ = @asyncCall(&frame, &result, callMainAsync, .{loop});257 _ = @asyncCall(&frame, &result, callMainAsync, .{ u8, mainFunc, loop });
238 loop.run();258 loop.run();
239 return result;259 return result;
240 }260 }
...@@ -242,13 +262,13 @@ inline fn initEventLoopAndCallMain() u8 {...@@ -242,13 +262,13 @@ inline fn initEventLoopAndCallMain() u8 {
242262
243 // This is marked inline because for some reason LLVM in release mode fails to inline it,263 // This is marked inline because for some reason LLVM in release mode fails to inline it,
244 // and we want fewer call frames in stack traces.264 // and we want fewer call frames in stack traces.
245 return @call(.{ .modifier = .always_inline }, callMain, .{});265 return @call(.{ .modifier = .always_inline }, mainFunc, .{});
246}266}
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 {
248 // This prevents the event loop from terminating at least until main() has returned.268 // This prevents the event loop from terminating at least until main() has returned.
249 loop.beginOneEvent();269 loop.beginOneEvent();
250 defer loop.finishOneEvent();270 defer loop.finishOneEvent();
251 return callMain();271 return mainProc();
252}272}
253273
254// This is not marked inline because it is called with @asyncCall when274// This is not marked inline because it is called with @asyncCall when
...@@ -290,3 +310,15 @@ pub fn callMain() u8 {...@@ -290,3 +310,15 @@ pub fn callMain() u8 {
290 else => @compileError(bad_main_ret),310 else => @compileError(bad_main_ret),
291 }311 }
292}312}
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 {...@@ -1097,17 +1097,13 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
1097 try argv.append("-NODEFAULTLIB");1097 try argv.append("-NODEFAULTLIB");
1098 if (!is_lib) {1098 if (!is_lib) {
1099 if (self.base.options.module) |module| {1099 if (self.base.options.module) |module| {
1100 if (module.stage1_flags.have_winmain) {1100 if (module.stage1_flags.have_winmain_crt_startup) {
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 {
1107 try argv.append("-ENTRY:WinMainCRTStartup");1101 try argv.append("-ENTRY:WinMainCRTStartup");
1102 } else {
1103 try argv.append("-ENTRY:wWinMainCRTStartup");
1108 }1104 }
1109 } else {1105 } else {
1110 try argv.append("-ENTRY:WinMainCRTStartup");1106 try argv.append("-ENTRY:wWinMainCRTStartup");
1111 }1107 }
1112 }1108 }
1113 }1109 }
test/stack_traces.zig+3-3
...@@ -282,10 +282,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -282,10 +282,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
282 \\source.zig:10:8: [address] in main (test)282 \\source.zig:10:8: [address] in main (test)
283 \\ foo();283 \\ foo();
284 \\ ^284 \\ ^
285 \\start.zig:269:29: [address] in std.start.posixCallMainAndExit (test)285 \\start.zig:289:29: [address] in std.start.posixCallMainAndExit (test)
286 \\ return root.main();286 \\ return root.main();
287 \\ ^287 \\ ^
288 \\start.zig:143:5: [address] in std.start._start (test)288 \\start.zig:151:5: [address] in std.start._start (test)
289 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});289 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
290 \\ ^290 \\ ^
291 \\291 \\
...@@ -294,7 +294,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -294,7 +294,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
294 switch (std.Target.current.cpu.arch) {294 switch (std.Target.current.cpu.arch) {
295 .aarch64 => "", // TODO disabled; results in segfault295 .aarch64 => "", // TODO disabled; results in segfault
296 else => 296 else =>
297 \\start.zig:143:5: [address] in std.start._start (test)297 \\start.zig:151:5: [address] in std.start._start (test)
298 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});298 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
299 \\ ^299 \\ ^
300 \\300 \\