diff --git a/lib/std/start.zig b/lib/std/start.zig index c22a36f24fd6..0288bcd349cb 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -37,8 +37,10 @@ comptime { @export(&main2, .{ .name = "main" }); } } else if (builtin.os.tag == .windows) { - if (!@hasDecl(root, "wWinMainCRTStartup") and !@hasDecl(root, "mainCRTStartup")) { - @export(&wWinMainCRTStartup2, .{ .name = "wWinMainCRTStartup" }); + if (!@hasDecl(root, "wWinMainCRTStartup") and !@hasDecl(root, "WinMainCRTStartup") and + !@hasDecl(root, "mainCRTStartup") and !@hasDecl(root, "wmainCRTStartup")) + { + @export(&WinStartup2, .{ .name = "wmainCRTStartup" }); } } else if (builtin.os.tag == .opencl or builtin.os.tag == .vulkan) { if (@hasDecl(root, "main")) @@ -65,7 +67,7 @@ comptime { if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) { - @export(&WinStartup, .{ .name = "wWinMainCRTStartup" }); + @export(&WinStartup, .{ .name = "wmainCRTStartup" }); } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) { @@ -113,7 +115,7 @@ fn spirvMain2() callconv(.kernel) void { root.main(); } -fn wWinMainCRTStartup2() callconv(.c) noreturn { +fn WinStartup2() callconv(.c) noreturn { std.posix.exit(callMain()); } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index a56311b32542..3ea6931cd499 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1642,6 +1642,8 @@ pub const Object = struct { if (name.eqlSlice("main", ip)) flags.c_main = true; if (name.eqlSlice("WinMain", ip)) flags.winmain = true; if (name.eqlSlice("wWinMain", ip)) flags.wwinmain = true; + if (name.eqlSlice("mainCRTStartup", ip)) flags.main_crt_startup = true; + if (name.eqlSlice("wmainCRTStartup", ip)) flags.wmain_crt_startup = true; if (name.eqlSlice("WinMainCRTStartup", ip)) flags.winmain_crt_startup = true; if (name.eqlSlice("wWinMainCRTStartup", ip)) flags.wwinmain_crt_startup = true; if (name.eqlSlice("DllMainCRTStartup", ip)) flags.dllmain_crt_startup = true; diff --git a/src/link/Lld.zig b/src/link/Lld.zig index d9c25f641d9e..983d84d8e11f 100644 --- a/src/link/Lld.zig +++ b/src/link/Lld.zig @@ -25,6 +25,8 @@ const Coff = struct { c_main: bool, winmain: bool, wwinmain: bool, + main_crt_startup: bool, + wmain_crt_startup: bool, winmain_crt_startup: bool, wwinmain_crt_startup: bool, dllmain_crt_startup: bool, @@ -64,6 +66,8 @@ const Coff = struct { .c_main = false, .winmain = false, .wwinmain = false, + .main_crt_startup = false, + .wmain_crt_startup = false, .winmain_crt_startup = false, .wwinmain_crt_startup = false, .dllmain_crt_startup = false, @@ -562,12 +566,14 @@ fn coffLink(lld: *Lld, arena: Allocator) !void { if (coff.lld_export_flags.dllmain_crt_startup or is_dyn_lib) break :blk null; if (coff.lld_export_flags.c_main or comp.config.is_test or - coff.lld_export_flags.winmain_crt_startup or - coff.lld_export_flags.wwinmain_crt_startup) + coff.lld_export_flags.main_crt_startup or + coff.lld_export_flags.wmain_crt_startup) { break :blk .console; } - if (coff.lld_export_flags.winmain or coff.lld_export_flags.wwinmain) + if (coff.lld_export_flags.winmain or coff.lld_export_flags.wwinmain or + coff.lld_export_flags.winmain_crt_startup or + coff.lld_export_flags.wwinmain_crt_startup) break :blk .windows; } }, @@ -660,13 +666,19 @@ fn coffLink(lld: *Lld, arena: Allocator) !void { try argv.append("-NODEFAULTLIB"); if (!is_lib and entry_name == null) { if (comp.zcu != null) { - if (coff.lld_export_flags.winmain_crt_startup) { + if (coff.lld_export_flags.wwinmain_crt_startup) { + try argv.append("-ENTRY:wWinMainCRTStartup"); + } else if (coff.lld_export_flags.winmain_crt_startup) { try argv.append("-ENTRY:WinMainCRTStartup"); + } else if (coff.lld_export_flags.wmain_crt_startup) { + try argv.append("-ENTRY:wmainCRTStartup"); + } else if (coff.lld_export_flags.main_crt_startup) { + try argv.append("-ENTRY:mainCRTStartup"); } else { - try argv.append("-ENTRY:wWinMainCRTStartup"); + try argv.append("-ENTRY:wmainCRTStartup"); } } else { - try argv.append("-ENTRY:wWinMainCRTStartup"); + try argv.append("-ENTRY:wmainCRTStartup"); } } } diff --git a/test/standalone/build.zig.zon b/test/standalone/build.zig.zon index 79b12385c25c..f23f87b14e40 100644 --- a/test/standalone/build.zig.zon +++ b/test/standalone/build.zig.zon @@ -120,6 +120,9 @@ .windows_spawn = .{ .path = "windows_spawn", }, + .windows_subsystem = .{ + .path = "windows_subsystem", + }, .windows_argv = .{ .path = "windows_argv", }, diff --git a/test/standalone/windows_subsystem/build.zig b/test/standalone/windows_subsystem/build.zig new file mode 100644 index 000000000000..85b4f08ce8ea --- /dev/null +++ b/test/standalone/windows_subsystem/build.zig @@ -0,0 +1,169 @@ +const std = @import("std"); +const builtin = @import("builtin"); + +pub fn build(b: *std.Build) void { + const test_step = b.step("test", "Test it"); + b.default_step = test_step; + + const optimize: std.builtin.OptimizeMode = .Debug; + const target = b.graph.host; + + if (builtin.os.tag != .windows) return; + + const expected_console_subsystem = std.fmt.comptimePrint("{}\n", .{@intFromEnum(std.coff.Subsystem.WINDOWS_CUI)}); + const expected_windows_subsystem = std.fmt.comptimePrint("{}\n", .{@intFromEnum(std.coff.Subsystem.WINDOWS_GUI)}); + + // Normal Zig main, no libc linked + { + const main_mod = b.createModule(.{ + .root_source_file = b.path("main.zig"), + .optimize = optimize, + .target = target, + }); + + const main_inferred = b.addExecutable(.{ + .name = "main_inferred", + .root_module = main_mod, + }); + const run_inferred = b.addRunArtifact(main_inferred); + run_inferred.expectStdErrEqual(expected_console_subsystem); + run_inferred.expectExitCode(0); + test_step.dependOn(&run_inferred.step); + + const main_console = b.addExecutable(.{ + .name = "main_console", + .root_module = main_mod, + }); + main_console.subsystem = .console; + const run_console = b.addRunArtifact(main_console); + run_console.expectStdErrEqual(expected_console_subsystem); + run_console.expectExitCode(0); + test_step.dependOn(&run_console.step); + + const main_windows = b.addExecutable(.{ + .name = "main_windows", + .root_module = main_mod, + }); + main_windows.subsystem = .windows; + const run_windows = b.addRunArtifact(main_windows); + run_windows.expectStdErrEqual(expected_windows_subsystem); + run_windows.expectExitCode(0); + test_step.dependOn(&run_windows.step); + } + + // Normal Zig main, libc linked + { + const main_link_libc_mod = b.createModule(.{ + .root_source_file = b.path("main.zig"), + .optimize = optimize, + .target = target, + .link_libc = true, + }); + + const main_link_libc_inferred = b.addExecutable(.{ + .name = "main_link_libc_inferred", + .root_module = main_link_libc_mod, + }); + const run_inferred = b.addRunArtifact(main_link_libc_inferred); + run_inferred.expectStdErrEqual(expected_console_subsystem); + run_inferred.expectExitCode(0); + test_step.dependOn(&run_inferred.step); + + const main_link_libc_console = b.addExecutable(.{ + .name = "main_link_libc_console", + .root_module = main_link_libc_mod, + }); + main_link_libc_console.subsystem = .console; + const run_console = b.addRunArtifact(main_link_libc_console); + run_console.expectStdErrEqual(expected_console_subsystem); + run_console.expectExitCode(0); + test_step.dependOn(&run_console.step); + + const main_link_libc_windows = b.addExecutable(.{ + .name = "main_link_libc_windows", + .root_module = main_link_libc_mod, + }); + main_link_libc_windows.subsystem = .windows; + const run_windows = b.addRunArtifact(main_link_libc_windows); + run_windows.expectStdErrEqual(expected_windows_subsystem); + run_windows.expectExitCode(0); + test_step.dependOn(&run_windows.step); + } + + // wWinMain + { + const winmain_mod = b.createModule(.{ + .root_source_file = b.path("winmain.zig"), + .optimize = optimize, + .target = target, + }); + + const winmain_inferred = b.addExecutable(.{ + .name = "winmain_inferred", + .root_module = winmain_mod, + }); + const run_inferred = b.addRunArtifact(winmain_inferred); + run_inferred.expectStdErrEqual(expected_windows_subsystem); + run_inferred.expectExitCode(0); + test_step.dependOn(&run_inferred.step); + + const winmain_console = b.addExecutable(.{ + .name = "winmain_console", + .root_module = winmain_mod, + }); + winmain_console.subsystem = .console; + const run_console = b.addRunArtifact(winmain_console); + run_console.expectStdErrEqual(expected_console_subsystem); + run_console.expectExitCode(0); + test_step.dependOn(&run_console.step); + + const winmain_windows = b.addExecutable(.{ + .name = "winmain_windows", + .root_module = winmain_mod, + }); + winmain_windows.subsystem = .windows; + const run_windows = b.addRunArtifact(winmain_windows); + run_windows.expectStdErrEqual(expected_windows_subsystem); + run_windows.expectExitCode(0); + test_step.dependOn(&run_windows.step); + } + + // exported callconv(.c) main, libc must be linked + { + const cmain_mod = b.createModule(.{ + .root_source_file = b.path("cmain.zig"), + .optimize = optimize, + .target = target, + .link_libc = true, + }); + + const cmain_inferred = b.addExecutable(.{ + .name = "cmain_inferred", + .root_module = cmain_mod, + }); + const run_inferred = b.addRunArtifact(cmain_inferred); + run_inferred.expectStdErrEqual(expected_console_subsystem); + run_inferred.expectExitCode(0); + test_step.dependOn(&run_inferred.step); + + const cmain_console = b.addExecutable(.{ + .name = "cmain_console", + .root_module = cmain_mod, + }); + cmain_console.subsystem = .console; + const run_console = b.addRunArtifact(cmain_console); + run_console.expectStdErrEqual(expected_console_subsystem); + run_console.expectExitCode(0); + test_step.dependOn(&run_console.step); + + const cmain_windows = b.addExecutable(.{ + .name = "cmain_windows", + .root_module = cmain_mod, + }); + cmain_windows.subsystem = .windows; + const run_windows = b.addRunArtifact(cmain_windows); + run_windows.expectStdErrEqual(expected_windows_subsystem); + run_windows.expectExitCode(0); + test_step.dependOn(&run_windows.step); + } +} diff --git a/test/standalone/windows_subsystem/cmain.zig b/test/standalone/windows_subsystem/cmain.zig new file mode 100644 index 000000000000..f54708e2f116 --- /dev/null +++ b/test/standalone/windows_subsystem/cmain.zig @@ -0,0 +1,6 @@ +const std = @import("std"); + +pub export fn main() callconv(.c) c_int { + std.debug.print("{}\n", .{std.os.windows.peb().ImageSubSystem}); + return 0; +} diff --git a/test/standalone/windows_subsystem/main.zig b/test/standalone/windows_subsystem/main.zig new file mode 100644 index 000000000000..46d15452e03b --- /dev/null +++ b/test/standalone/windows_subsystem/main.zig @@ -0,0 +1,5 @@ +const std = @import("std"); + +pub fn main() void { + std.debug.print("{}\n", .{std.os.windows.peb().ImageSubSystem}); +} diff --git a/test/standalone/windows_subsystem/winmain.zig b/test/standalone/windows_subsystem/winmain.zig new file mode 100644 index 000000000000..b6dabf80a666 --- /dev/null +++ b/test/standalone/windows_subsystem/winmain.zig @@ -0,0 +1,15 @@ +const std = @import("std"); + +pub fn wWinMain( + inst: std.os.windows.HINSTANCE, + prev: ?std.os.windows.HINSTANCE, + cmd_line: std.os.windows.LPWSTR, + cmd_show: c_int, +) std.os.windows.INT { + _ = inst; + _ = prev; + _ = cmd_line; + _ = cmd_show; + std.debug.print("{}\n", .{std.os.windows.peb().ImageSubSystem}); + return 0; +}