From 2ad00dc62823820e324c0755c67041b59e152c8e Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Fri, 24 Apr 2026 14:01:38 +0900 Subject: [PATCH] address review: port win32 apprt to zigwin32 Per @marler8997 and @jcollie, use the marlersoft/zigwin32 bindings instead of hand-rolled extern decls for the Win32 API. Drops the inline type / constant / function declarations in App.zig and Surface.zig in favor of `@import("win32").everything`. The binding is declared lazy in build.zig.zon so it's only fetched when building the win32 apprt. Net effect: -240 / +101 lines. Type-safe style flags (packed structs for `WNDCLASS_STYLES`, `WINDOW_STYLE`, pixel format flags) replace raw OR'd u32 constants. Also clears a known Zig 0.16 risk since std.os.windows is shedding symbols the earlier code was relying on (pointed out in jcollie's review note). Co-authored-by: Claude --- build.zig.zon | 6 ++ src/apprt/win32/App.zig | 201 ++++++++++-------------------------- src/apprt/win32/Surface.zig | 131 +++++++---------------- src/build/SharedDeps.zig | 3 + 4 files changed, 101 insertions(+), 240 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 9d8d20c39..1faeef2b2 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -61,6 +61,12 @@ .hash = "gobject-0.3.0-Skun7ANLnwDvEfIpVmohcppXgOvg_I6YOJFmPIsKfXk-", .lazy = true, }, + .win32 = .{ + // marlersoft/zigwin32 -- Win32 API bindings for the win32 apprt. + .url = "git+https://github.com/marlersoft/zigwin32#ec98bb4d9eea532320a8551720a9e3ec6de64994", + .hash = "win32-25.0.28-preview-mX5pFWMt5QPTVIGh3r2-OpPunpcCCjApyRbA6Zn6WALH", + .lazy = true, + }, // C libs .dcimgui = .{ .path = "./pkg/dcimgui", .lazy = true }, diff --git a/src/apprt/win32/App.zig b/src/apprt/win32/App.zig index 72a5711ac..d334f4a8c 100644 --- a/src/apprt/win32/App.zig +++ b/src/apprt/win32/App.zig @@ -4,6 +4,7 @@ const App = @This(); const std = @import("std"); const builtin = @import("builtin"); +const win32 = @import("win32").everything; const Allocator = std.mem.Allocator; const apprt = @import("../../apprt.zig"); const configpkg = @import("../../config.zig"); @@ -15,109 +16,9 @@ const renderer = @import("../../renderer.zig"); const log = std.log.scoped(.win32); -// Win32 type definitions -const BOOL = i32; -const UINT = u32; -const DWORD = u32; -const WPARAM = usize; -const LPARAM = isize; -const LRESULT = isize; -const HWND = std.os.windows.HWND; -const HINSTANCE = std.os.windows.HINSTANCE; -const HICON = ?*anyopaque; -const HCURSOR = ?*anyopaque; -const HBRUSH = ?*anyopaque; -const HDC = ?*anyopaque; -const HMENU = ?*anyopaque; -const ATOM = u16; -const LONG_PTR = isize; - -const POINT = extern struct { - x: i32, - y: i32, -}; - -const MSG = extern struct { - hwnd: ?HWND, - message: UINT, - wParam: WPARAM, - lParam: LPARAM, - time: DWORD, - pt: POINT, -}; - -const RECT = extern struct { - left: i32, - top: i32, - right: i32, - bottom: i32, -}; - -const PAINTSTRUCT = extern struct { - hdc: HDC, - fErase: BOOL, - rcPaint: RECT, - fRestore: BOOL, - fIncUpdate: BOOL, - rgbReserved: [32]u8, -}; - -const WNDPROC = *const fn (HWND, UINT, WPARAM, LPARAM) callconv(.winapi) LRESULT; - -const WNDCLASSEXW = extern struct { - cbSize: UINT, - style: UINT, - lpfnWndProc: WNDPROC, - cbClsExtra: c_int, - cbWndExtra: c_int, - hInstance: ?HINSTANCE, - hIcon: HICON, - hCursor: HCURSOR, - hbrBackground: HBRUSH, - lpszMenuName: ?[*:0]const u16, - lpszClassName: [*:0]const u16, - hIconSm: HICON, -}; - -// Win32 constants -const WM_CLOSE = 0x0010; -const WM_DESTROY = 0x0002; -const WM_PAINT = 0x000F; -const WM_SIZE = 0x0005; -const WM_KEYDOWN = 0x0100; -const WM_CHAR = 0x0102; -const WM_USER = 0x0400; -const WM_WAKEUP = WM_USER + 1; -const CS_HREDRAW = 0x0002; -const CS_VREDRAW = 0x0001; -const CS_OWNDC = 0x0020; -const WS_OVERLAPPEDWINDOW = 0x00CF0000; -const CW_USEDEFAULT: i32 = @bitCast(@as(u32, 0x80000000)); -const SW_SHOWNORMAL = 1; -const IDC_ARROW: ?[*:0]align(1) const u16 = @ptrFromInt(32512); -const GWLP_USERDATA: c_int = -21; - -// Win32 API extern declarations -extern "user32" fn RegisterClassExW(lpWndClass: *const WNDCLASSEXW) callconv(.winapi) ATOM; -extern "user32" fn CreateWindowExW(dwExStyle: DWORD, lpClassName: ?[*:0]const u16, lpWindowName: ?[*:0]const u16, dwStyle: DWORD, x: i32, y: i32, nWidth: i32, nHeight: i32, hWndParent: ?HWND, hMenu: HMENU, hInstance: ?HINSTANCE, lpParam: ?*anyopaque) callconv(.winapi) ?HWND; -extern "user32" fn ShowWindow(hWnd: HWND, nCmdShow: c_int) callconv(.winapi) BOOL; -extern "user32" fn UpdateWindow(hWnd: HWND) callconv(.winapi) BOOL; -extern "user32" fn DestroyWindow(hWnd: HWND) callconv(.winapi) BOOL; -extern "user32" fn DefWindowProcW(hWnd: HWND, msg: UINT, wParam: WPARAM, lParam: LPARAM) callconv(.winapi) LRESULT; -extern "user32" fn GetMessageW(lpMsg: *MSG, hWnd: ?HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) callconv(.winapi) BOOL; -extern "user32" fn TranslateMessage(lpMsg: *const MSG) callconv(.winapi) BOOL; -extern "user32" fn DispatchMessageW(lpMsg: *const MSG) callconv(.winapi) LRESULT; -extern "user32" fn PostMessageW(hWnd: HWND, msg: UINT, wParam: WPARAM, lParam: LPARAM) callconv(.winapi) BOOL; -extern "user32" fn PostQuitMessage(nExitCode: c_int) callconv(.winapi) void; -extern "user32" fn BeginPaint(hWnd: HWND, lpPaint: *PAINTSTRUCT) callconv(.winapi) HDC; -extern "user32" fn EndPaint(hWnd: HWND, lpPaint: *const PAINTSTRUCT) callconv(.winapi) BOOL; -extern "user32" fn LoadCursorW(hInstance: ?HINSTANCE, lpCursorName: ?[*:0]align(1) const u16) callconv(.winapi) HCURSOR; -extern "user32" fn SetWindowLongPtrW(hWnd: HWND, nIndex: c_int, dwNewLong: LONG_PTR) callconv(.winapi) LONG_PTR; -extern "user32" fn GetWindowLongPtrW(hWnd: HWND, nIndex: c_int) callconv(.winapi) LONG_PTR; -extern "user32" fn GetClientRect(hWnd: HWND, lpRect: *RECT) callconv(.winapi) BOOL; -extern "user32" fn InvalidateRect(hWnd: ?HWND, lpRect: ?*const RECT, bErase: BOOL) callconv(.winapi) BOOL; -extern "kernel32" fn GetModuleHandleW(lpModuleName: ?[*:0]const u16) callconv(.winapi) ?HINSTANCE; -extern "kernel32" fn GetLastError() callconv(.winapi) DWORD; +/// User-defined wakeup message sent via PostMessage to break out of +/// GetMessage and run the core app's tick. +const WM_WAKEUP = win32.WM_USER + 1; /// The core app instance. core_app: *CoreApp, @@ -132,7 +33,7 @@ alloc: Allocator, running: bool = true, /// The main window handle. -hwnd: ?HWND = null, +hwnd: ?win32.HWND = null, /// The surface for the main window. surface: Surface = undefined, @@ -165,8 +66,14 @@ pub fn init( // Initialize the surface with OpenGL try self.surface.init(self.hwnd.?); - // Store self pointer in window for use in wndProc - _ = SetWindowLongPtrW(self.hwnd.?, GWLP_USERDATA, @bitCast(@intFromPtr(self))); + // Store self pointer in window for use in wndProc. SetWindowLongPtrW + // returns the previous value, which for a freshly created window is 0; + // we don't care about it here. + _ = win32.SetWindowLongPtrW( + self.hwnd.?, + win32.GWLP_USERDATA, + @bitCast(@intFromPtr(self)), + ); // Initialize the core surface (terminal emulation + rendering) try self.initCoreSurface(); @@ -176,27 +83,27 @@ pub fn run(self: *App) !void { log.info("starting Win32 event loop", .{}); while (self.running) { - var msg: MSG = std.mem.zeroes(MSG); - const ret = GetMessageW(&msg, null, 0, 0); + var msg: win32.MSG = std.mem.zeroes(win32.MSG); + const ret = win32.GetMessageW(&msg, null, 0, 0); if (ret == 0) { // WM_QUIT self.running = false; break; } if (ret == -1) { - log.err("GetMessage failed", .{}); + log.err("GetMessage failed: err={d}", .{@intFromEnum(win32.GetLastError())}); return error.Win32Error; } - _ = TranslateMessage(&msg); - _ = DispatchMessageW(&msg); + _ = win32.TranslateMessage(&msg); + _ = win32.DispatchMessageW(&msg); } } pub fn terminate(self: *App) void { self.surface.deinit(); if (self.hwnd) |hwnd| { - if (DestroyWindow(hwnd) == 0) { - log.warn("DestroyWindow failed: err={d}", .{GetLastError()}); + if (win32.DestroyWindow(hwnd) == 0) { + log.warn("DestroyWindow failed: err={d}", .{@intFromEnum(win32.GetLastError())}); } self.hwnd = null; } @@ -206,8 +113,8 @@ pub fn terminate(self: *App) void { pub fn wakeup(self: *App) void { if (self.hwnd) |hwnd| { - if (PostMessageW(hwnd, WM_WAKEUP, 0, 0) == 0) { - log.warn("PostMessage(WM_WAKEUP) failed: err={d}", .{GetLastError()}); + if (win32.PostMessageW(hwnd, WM_WAKEUP, 0, 0) == 0) { + log.warn("PostMessage(WM_WAKEUP) failed: err={d}", .{@intFromEnum(win32.GetLastError())}); } } } @@ -224,7 +131,7 @@ pub fn performAction( switch (action) { .quit => { - PostQuitMessage(0); + win32.PostQuitMessage(0); return true; }, .new_window => { @@ -287,68 +194,66 @@ fn initCoreSurface(self: *App) !void { } fn createWindow(self: *App) !void { - const class_name = std.unicode.utf8ToUtf16LeStringLiteral("GhosttyWindow"); - const hinstance = GetModuleHandleW(null); + const class_name = win32.L("GhosttyWindow"); + const hinstance = win32.GetModuleHandleW(null); - const wc: WNDCLASSEXW = .{ - .cbSize = @sizeOf(WNDCLASSEXW), - .style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC, + const wc: win32.WNDCLASSEXW = .{ + .cbSize = @sizeOf(win32.WNDCLASSEXW), + .style = .{ .HREDRAW = 1, .VREDRAW = 1, .OWNDC = 1 }, .lpfnWndProc = wndProc, .cbClsExtra = 0, .cbWndExtra = 0, .hInstance = hinstance, .hIcon = null, - .hCursor = LoadCursorW(null, IDC_ARROW), + .hCursor = win32.LoadCursorW(null, win32.IDC_ARROW), .hbrBackground = null, .lpszMenuName = null, .lpszClassName = class_name, .hIconSm = null, }; - if (RegisterClassExW(&wc) == 0) { - log.err("RegisterClassEx failed", .{}); + if (win32.RegisterClassExW(&wc) == 0) { + log.err("RegisterClassExW failed: err={d}", .{@intFromEnum(win32.GetLastError())}); return error.Win32Error; } - const title = std.unicode.utf8ToUtf16LeStringLiteral("Ghostty"); + const title = win32.L("Ghostty"); - self.hwnd = CreateWindowExW( - 0, + self.hwnd = win32.CreateWindowExW( + .{}, class_name, title, - WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, - CW_USEDEFAULT, + win32.WS_OVERLAPPEDWINDOW, + win32.CW_USEDEFAULT, + win32.CW_USEDEFAULT, 800, 600, null, null, hinstance, null, - ); - - if (self.hwnd == null) { - log.err("CreateWindowEx failed", .{}); + ) orelse { + log.err("CreateWindowExW failed: err={d}", .{@intFromEnum(win32.GetLastError())}); return error.Win32Error; - } + }; - _ = ShowWindow(self.hwnd.?, SW_SHOWNORMAL); - _ = UpdateWindow(self.hwnd.?); + _ = win32.ShowWindow(self.hwnd.?, win32.SW_SHOWNORMAL); + _ = win32.UpdateWindow(self.hwnd.?); } -fn getApp(hwnd: HWND) ?*App { - const ptr = GetWindowLongPtrW(hwnd, GWLP_USERDATA); +fn getApp(hwnd: win32.HWND) ?*App { + const ptr = win32.GetWindowLongPtrW(hwnd, win32.GWLP_USERDATA); if (ptr == 0) return null; return @ptrFromInt(@as(usize, @bitCast(ptr))); } -fn wndProc(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) callconv(.winapi) LRESULT { +fn wndProc(hwnd: win32.HWND, msg: u32, wparam: win32.WPARAM, lparam: win32.LPARAM) callconv(.winapi) win32.LRESULT { switch (msg) { - WM_CLOSE => { - PostQuitMessage(0); + win32.WM_CLOSE => { + win32.PostQuitMessage(0); return 0; }, - WM_SIZE => { + win32.WM_SIZE => { if (getApp(hwnd)) |app| { const width: u32 = @intCast(lparam & 0xFFFF); const height: u32 = @intCast((lparam >> 16) & 0xFFFF); @@ -367,13 +272,13 @@ fn wndProc(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) callconv(.wina } return 0; }, - WM_PAINT => { - var ps: PAINTSTRUCT = std.mem.zeroes(PAINTSTRUCT); - _ = BeginPaint(hwnd, &ps); + win32.WM_PAINT => { + var ps: win32.PAINTSTRUCT = std.mem.zeroes(win32.PAINTSTRUCT); + _ = win32.BeginPaint(hwnd, &ps); if (getApp(hwnd)) |app| { app.surface.swapBuffers(); } - _ = EndPaint(hwnd, &ps); + _ = win32.EndPaint(hwnd, &ps); return 0; }, WM_WAKEUP => { @@ -384,6 +289,6 @@ fn wndProc(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) callconv(.wina } return 0; }, - else => return DefWindowProcW(hwnd, msg, wparam, lparam), + else => return win32.DefWindowProcW(hwnd, msg, wparam, lparam), } } diff --git a/src/apprt/win32/Surface.zig b/src/apprt/win32/Surface.zig index 80d86945e..45b37e645 100644 --- a/src/apprt/win32/Surface.zig +++ b/src/apprt/win32/Surface.zig @@ -4,6 +4,7 @@ const Self = @This(); const std = @import("std"); +const win32 = @import("win32").everything; const Allocator = std.mem.Allocator; const apprt = @import("../../apprt.zig"); const configpkg = @import("../../config.zig"); @@ -12,71 +13,17 @@ const CoreApp = @import("../../App.zig"); const log = std.log.scoped(.win32_surface); -// Win32 types -const HWND = std.os.windows.HWND; -const HINSTANCE = std.os.windows.HINSTANCE; -const BOOL = i32; -const HDC = ?*anyopaque; -const HGLRC = ?*anyopaque; - -const PIXELFORMATDESCRIPTOR = extern struct { - nSize: u16, - nVersion: u16, - dwFlags: u32, - iPixelType: u8, - cColorBits: u8, - cRedBits: u8, - cRedShift: u8, - cGreenBits: u8, - cGreenShift: u8, - cBlueBits: u8, - cBlueShift: u8, - cAlphaBits: u8, - cAlphaShift: u8, - cAccumBits: u8, - cAccumRedBits: u8, - cAccumGreenBits: u8, - cAccumBlueBits: u8, - cAccumAlphaBits: u8, - cDepthBits: u8, - cStencilBits: u8, - cAuxBuffers: u8, - iLayerType: u8, - bReserved: u8, - dwLayerMask: u32, - dwVisibleMask: u32, - dwDamageMask: u32, -}; - -// WGL / GDI constants -const PFD_DRAW_TO_WINDOW = 0x00000004; -const PFD_SUPPORT_OPENGL = 0x00000020; -const PFD_DOUBLEBUFFER = 0x00000001; -const PFD_TYPE_RGBA = 0; -const PFD_MAIN_PLANE = 0; - -// WGL / GDI extern declarations -extern "user32" fn GetDC(hWnd: ?HWND) callconv(.winapi) HDC; -extern "user32" fn ReleaseDC(hWnd: ?HWND, hDC: HDC) callconv(.winapi) c_int; -extern "gdi32" fn ChoosePixelFormat(hdc: HDC, ppfd: *const PIXELFORMATDESCRIPTOR) callconv(.winapi) c_int; -extern "gdi32" fn SetPixelFormat(hdc: HDC, format: c_int, ppfd: *const PIXELFORMATDESCRIPTOR) callconv(.winapi) BOOL; -extern "gdi32" fn SwapBuffers(hdc: HDC) callconv(.winapi) BOOL; -extern "opengl32" fn wglCreateContext(hdc: HDC) callconv(.winapi) HGLRC; -extern "opengl32" fn wglDeleteContext(hglrc: HGLRC) callconv(.winapi) BOOL; -extern "opengl32" fn wglMakeCurrent(hdc: HDC, hglrc: HGLRC) callconv(.winapi) BOOL; -extern "kernel32" fn GetLastError() callconv(.winapi) u32; - /// The window this surface belongs to. -hwnd: HWND, +hwnd: win32.HWND, /// Pointer back to the App. app: ?*App = null, /// GDI device context. -hdc: HDC = null, +hdc: ?win32.HDC = null, /// OpenGL rendering context. -hglrc: HGLRC = null, +hglrc: ?win32.HGLRC = null, /// The core surface, if initialized. core_surface: ?*CoreSurface = null, @@ -95,7 +42,7 @@ pub fn rtApp(self: *Self) *App { return self.app.?; } -pub fn init(self: *Self, hwnd: HWND) !void { +pub fn init(self: *Self, hwnd: win32.HWND) !void { self.* = .{ .hwnd = hwnd }; try self.initOpenGL(); } @@ -105,51 +52,49 @@ pub fn deinit(self: *Self) void { surface.deinit(); // core_surface is allocated by CoreApp, freed there } - if (self.hglrc != null) { - _ = wglMakeCurrent(null, null); - _ = wglDeleteContext(self.hglrc); + if (self.hglrc) |hglrc| { + _ = win32.wglMakeCurrent(null, null); + _ = win32.wglDeleteContext(hglrc); } - if (self.hdc != null) { - _ = ReleaseDC(self.hwnd, self.hdc); + if (self.hdc) |hdc| { + _ = win32.ReleaseDC(self.hwnd, hdc); } } fn initOpenGL(self: *Self) !void { - self.hdc = GetDC(self.hwnd); - if (self.hdc == null) { - log.err("GetDC failed", .{}); + self.hdc = win32.GetDC(self.hwnd) orelse { + log.err("GetDC failed: err={d}", .{@intFromEnum(win32.GetLastError())}); return error.Win32Error; - } + }; - var pfd: PIXELFORMATDESCRIPTOR = std.mem.zeroes(PIXELFORMATDESCRIPTOR); - pfd.nSize = @sizeOf(PIXELFORMATDESCRIPTOR); + var pfd: win32.PIXELFORMATDESCRIPTOR = std.mem.zeroes(win32.PIXELFORMATDESCRIPTOR); + pfd.nSize = @sizeOf(win32.PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_RGBA; + pfd.dwFlags = .{ .DRAW_TO_WINDOW = 1, .SUPPORT_OPENGL = 1, .DOUBLEBUFFER = 1 }; + pfd.iPixelType = .RGBA; pfd.cColorBits = 32; pfd.cDepthBits = 24; pfd.cStencilBits = 8; - pfd.iLayerType = PFD_MAIN_PLANE; + pfd.iLayerType = .MAIN_PLANE; - const pixel_format = ChoosePixelFormat(self.hdc, &pfd); + const pixel_format = win32.ChoosePixelFormat(self.hdc, &pfd); if (pixel_format == 0) { - log.err("ChoosePixelFormat failed", .{}); + log.err("ChoosePixelFormat failed: err={d}", .{@intFromEnum(win32.GetLastError())}); return error.Win32Error; } - if (SetPixelFormat(self.hdc, pixel_format, &pfd) == 0) { - log.err("SetPixelFormat failed", .{}); + if (win32.SetPixelFormat(self.hdc, pixel_format, &pfd) == 0) { + log.err("SetPixelFormat failed: err={d}", .{@intFromEnum(win32.GetLastError())}); return error.Win32Error; } - self.hglrc = wglCreateContext(self.hdc); - if (self.hglrc == null) { - log.err("wglCreateContext failed", .{}); + self.hglrc = win32.wglCreateContext(self.hdc) orelse { + log.err("wglCreateContext failed: err={d}", .{@intFromEnum(win32.GetLastError())}); return error.Win32Error; - } + }; - if (wglMakeCurrent(self.hdc, self.hglrc) == 0) { - log.err("wglMakeCurrent failed", .{}); + if (win32.wglMakeCurrent(self.hdc, self.hglrc) == 0) { + log.err("wglMakeCurrent failed: err={d}", .{@intFromEnum(win32.GetLastError())}); return error.Win32Error; } @@ -157,34 +102,36 @@ fn initOpenGL(self: *Self) !void { } pub fn swapBuffers(self: *Self) void { - if (self.hdc != null) { - if (SwapBuffers(self.hdc) == 0) { - log.warn("SwapBuffers failed: err={d}", .{GetLastError()}); + if (self.hdc) |hdc| { + if (win32.SwapBuffers(hdc) == 0) { + log.warn("SwapBuffers failed: err={d}", .{@intFromEnum(win32.GetLastError())}); } } } /// Make the WGL context current on the calling thread. pub fn makeContextCurrent(self: *Self) void { - if (self.hdc != null and self.hglrc != null) { - if (wglMakeCurrent(self.hdc, self.hglrc) == 0) { - log.warn("wglMakeCurrent failed: err={d}", .{GetLastError()}); + if (self.hdc) |hdc| { + if (self.hglrc) |hglrc| { + if (win32.wglMakeCurrent(hdc, hglrc) == 0) { + log.warn("wglMakeCurrent failed: err={d}", .{@intFromEnum(win32.GetLastError())}); + } } } } /// Release the WGL context from the calling thread. pub fn releaseContext() void { - if (wglMakeCurrent(null, null) == 0) { - log.warn("wglMakeCurrent(null) failed: err={d}", .{GetLastError()}); + if (win32.wglMakeCurrent(null, null) == 0) { + log.warn("wglMakeCurrent(null) failed: err={d}", .{@intFromEnum(win32.GetLastError())}); } } /// Release context from the main thread before handing off to renderer thread. pub fn releaseMainThreadContext(self: *Self) void { _ = self; - if (wglMakeCurrent(null, null) == 0) { - log.warn("wglMakeCurrent(null) failed: err={d}", .{GetLastError()}); + if (win32.wglMakeCurrent(null, null) == 0) { + log.warn("wglMakeCurrent(null) failed: err={d}", .{@intFromEnum(win32.GetLastError())}); } } diff --git a/src/build/SharedDeps.zig b/src/build/SharedDeps.zig index 0bea64753..b0496baa3 100644 --- a/src/build/SharedDeps.zig +++ b/src/build/SharedDeps.zig @@ -609,6 +609,9 @@ pub fn add( step.linkSystemLibrary2("user32", .{}); step.linkSystemLibrary2("gdi32", .{}); step.linkSystemLibrary2("opengl32", .{}); + if (b.lazyDependency("win32", .{})) |dep| { + step.root_module.addImport("win32", dep.module("win32")); + } }, } }