Commit b31a03f134

Ryan Liptak <squeek502@hotmail.com>
2025-11-08 10:39:15
Let CRT take care of the entry point for wWinMain if libc is linked
Fixes #7852 Before, the modified test would fail with: ``` error: lld-link: undefined symbol: wWinMain note: referenced by C:\Users\Ryan\Programming\Zig\zig-x86_64-windows-0.15.1\lib\libc\mingw\crt\crtexewin.c:66 note: libmingw32.lib(ucrtexewin.obj):(wmain) ```
1 parent be4eaed
Changed files (4)
lib
test
standalone
windows_entry_points
lib/std/start.zig
@@ -61,6 +61,10 @@ comptime {
                 } else if (!@typeInfo(@TypeOf(root.main)).@"fn".calling_convention.eql(.c)) {
                     @export(&main, .{ .name = "main" });
                 }
+            } else if (native_os == .windows and builtin.link_libc and @hasDecl(root, "wWinMain")) {
+                if (!@typeInfo(@TypeOf(root.wWinMain)).@"fn".calling_convention.eql(.c)) {
+                    @export(&wWinMain, .{ .name = "wWinMain" });
+                }
             } else if (native_os == .windows) {
                 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
                     !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
@@ -527,6 +531,10 @@ fn wWinMainCRTStartup() callconv(.withStackAlign(.c, 1)) noreturn {
     std.os.windows.ntdll.RtlExitUserProcess(@as(std.os.windows.UINT, @bitCast(result)));
 }
 
+fn wWinMain(hInstance: *anyopaque, hPrevInstance: ?*anyopaque, pCmdLine: [*:0]u16, nCmdShow: c_int) callconv(.c) c_int {
+    return root.wWinMain(@ptrCast(hInstance), @ptrCast(hPrevInstance), pCmdLine, @intCast(nCmdShow));
+}
+
 fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
     // We're not ready to panic until thread local storage is initialized.
     @setRuntimeSafety(false);
test/standalone/windows_entry_points/build.zig
@@ -77,4 +77,66 @@ pub fn build(b: *std.Build) void {
         _ = exe.getEmittedBin();
         test_step.dependOn(&exe.step);
     }
+
+    {
+        const exe = b.addExecutable(.{
+            .name = "zig_main",
+            .root_module = b.createModule(.{
+                .root_source_file = b.path("main.zig"),
+                .target = target,
+                .optimize = .Debug,
+            }),
+        });
+
+        _ = exe.getEmittedBin();
+        test_step.dependOn(&exe.step);
+    }
+
+    {
+        const exe = b.addExecutable(.{
+            .name = "zig_main_link_libc",
+            .root_module = b.createModule(.{
+                .root_source_file = b.path("main.zig"),
+                .target = target,
+                .optimize = .Debug,
+                .link_libc = true,
+            }),
+        });
+
+        _ = exe.getEmittedBin();
+        test_step.dependOn(&exe.step);
+    }
+
+    {
+        const exe = b.addExecutable(.{
+            .name = "zig_wwinmain",
+            .root_module = b.createModule(.{
+                .root_source_file = b.path("wwinmain.zig"),
+                .target = target,
+                .optimize = .Debug,
+            }),
+        });
+        exe.mingw_unicode_entry_point = true;
+        // Note: `exe.subsystem = .windows;` is not necessary
+
+        _ = exe.getEmittedBin();
+        test_step.dependOn(&exe.step);
+    }
+
+    {
+        const exe = b.addExecutable(.{
+            .name = "zig_wwinmain_link_libc",
+            .root_module = b.createModule(.{
+                .root_source_file = b.path("wwinmain.zig"),
+                .target = target,
+                .optimize = .Debug,
+                .link_libc = true,
+            }),
+        });
+        exe.mingw_unicode_entry_point = true;
+        // Note: `exe.subsystem = .windows;` is not necessary
+
+        _ = exe.getEmittedBin();
+        test_step.dependOn(&exe.step);
+    }
 }
test/standalone/windows_entry_points/main.zig
@@ -0,0 +1,5 @@
+const std = @import("std");
+
+pub fn main() void {
+    std.debug.print("hello from Zig main\n", .{});
+}
test/standalone/windows_entry_points/wwinmain.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("hello from Zig wWinMain\n", .{});
+    return 0;
+}