ludic/changes/windows-target.md
Orkuncakilkaya 00d25dcc3e feat(windows): a window - win32.ll, WGL on it, and a windowed Windows build
win32.ll implements cocoa.ll's contracts over user32 and xinput: the message
pump, the held-key set and frame key in Ludic codes, the mouse with raw input
for cursor mode 2, clip-based cursor modes released on focus loss, XInput pads,
and the software framebuffer present. win32_gl.ll puts the WGL 4.1 core context
on that window (vsync, borderless full screen); gl_win.ll's context code is now
lgl_wgl_core, shared with the headless hidden window, whose win_gl_* stubs move
to gl_win_nowin.ll. audio_win.ll links Audio.* silently for now.

Verified: macOS fixpoint, ludic-dev test 135/135, selfhost-test 32/32; on the
PC gl_triangle renders identically headless and in a real window, and Maroon
Lake builds windowed and runs a playtest to frame 240 in the desktop session.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 02:33:53 +03:00

2.4 KiB

bump: minor type: feat Windows target — ludicc builds and runs headless programs on Windows, and builds itself there.

  • --target <triple> — a triple naming windows selects the Windows runtime; without the flag the target is the host, read at run time from OS=Windows_NT. The IR still carries no triple, so clang assembles it for the machine it runs on.
  • The libc surface, in IR — on Windows the header emits emit_win.ludic, which defines the POSIX names the backend calls (fopen, ftell, rename, opendir, mmap, fmemopen, uname, …) over the UCRT and Win32. Three of them fixed silent breakage rather than link errors: rename onto an existing file (every Fs.write_text after the first), a 32-bit ftell, and text-mode fopen rewriting \n as \r\n.
  • Known folders — Os.save_dir / config_dir are %APPDATA%\<app>, cache_dir is %LOCALAPPDATA%\<app>, temp_dir is %TEMP%, all with forward slashes; a bundle's home line points at %APPDATA%\<name>.
  • The driver — finds C:\Program Files\LLVM\bin\clang.exe when clang is not on %PATH%, writes .exe outputs, speaks cmd.exe for its directory and cleanup commands, and reads argv[0], %PATH% and $LUDIC_HOME with either separator.
  • A window — win32.ll is cocoa.ll's contract over user32: the held-key set and frame key in Ludic codes, the mouse in framebuffer pixels with raw input for cursor mode 2, cursor hide/lock/confine that lets go when the window loses the foreground, XInput pads in SDL order with rescaled deadzones, and the software win_present. win32_gl.ll puts the WGL context on that window with vsync and borderless full screen; a headless build links gl_win_nowin.ll instead. The process is per-monitor DPI aware.
  • Not yet — Audio.* links and is silent (audio_win.ll), the splash and App.set_icon do nothing, and Http.* is still a macOS platform layer; a Windows build that uses it stops with a message saying so.
  • Gl.* on Windows — gl_win.ll makes a WGL 4.1 core context on a hidden window's DC, and gl_thunks_win.ll (generated by ludic-dev glgen beside gl_thunks.ll) calls every entry point through a table @lgl_win_load fills from wglGetProcAddress, falling back to opengl32.dll for the 1.1 functions it will not return. A headless GL program renders on the GPU there: gl_triangle matches the macOS frame to within one level per channel.