Skip to content

Windows: build and run natively - #33

Open
endel wants to merge 1 commit into
mainfrom
windows-support
Open

endel wants to merge 1 commit into
mainfrom
windows-support

Conversation

@endel

@endel endel commented Sep 14, 2026

Copy link
Copy Markdown
Owner

Summary

quic-zig now builds, tests and runs natively on Windows, and CI gains a windows-latest job.

  • Syscall seam. src/sys.zig had a compile error on every Windows branch. Windows now lives in src/sys/windows.zig: Winsock for sockets (Zig 0.16 dropped the ws2_32 bindings, so the few we call are declared there), std.Io for files, clocks, randomness and sleep. The 20 per-function OS switches became one supported-OS check.
  • Helpers instead of repeated POSIX setup. sys.udpSocket, setsockopt, setReuseAddr, stdout and argsIterator replace socket setup, IPV6_V6ONLY magic numbers and argument parsing that were copied across src/ and 26 apps.
  • Event loop. It waits for readiness (xev.File.poll), which libxev's IOCP backend lacked. build.zig.zon pins endel/libxev@14899db, which adds poll through the AFD driver — proposed upstream in iocp: add poll, through the AFD driver mitchellh/libxev#240. Once that merges, the pin can go back to upstream.

Windows behaviour worth knowing

Documented in SPEC/STATUS.md#platforms:

  • A UDP socket no longer fails its next receive after an ICMP port-unreachable (SIO_UDP_CONNRESET), so one departed client cannot break a server's receive loop.
  • SO_REUSEADDR is not set: on Windows it lets another socket take a port that is in use.
  • ECN is neither read nor set; there is no send batching or UDP offload.
  • Sleeps and timed waits round to the ~15.6 ms system tick, which makes the manual-loop bench app slow on Windows.

Testing

  • Windows (Zig 0.16.0): zig build test 757/757, zig build fuzz 612/612, every app builds; server + bench completed 1000/1000 requests in 1-RTT and 0-RTT.
  • Linux (WSL, Zig 0.16.0): zig build test 757/757, every app builds.
  • macOS: not run locally — covered by CI.

WebTransport echo latency, wt-echo-server (ReleaseFast) vs quic-go v0.59.0 wt_server, same Go wt_latency client, loopback, medians:

quic-zig datagram quic-go datagram quic-zig bidi quic-go bidi
Windows (5×1000) 117–214 µs 147–226 µs 132–230 µs 179–312 µs
Linux (3×1000) 137–139 µs 195–202 µs 152–155 µs 239–248 µs

On Windows the client timed with QueryPerformanceCounter; Go's own clock there is too coarse for sub-millisecond round trips.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YXLKbmpkRS5DedisNs9VNp

sys.zig was POSIX-only, with a compile error on every Windows branch. Windows
now lives in sys/windows.zig: Winsock for sockets, std.Io for files, clocks,
randomness and sleep. Callers go through new helpers instead of spelling out
POSIX socket setup — udpSocket, setsockopt, setReuseAddr, stdout and
argsIterator — which replaced setup code repeated across src and 26 apps.

The event loop waits for readiness, which libxev's IOCP backend lacked, so
build.zig.zon pins a libxev fork that adds poll through the AFD driver.

On Windows a UDP socket no longer fails its next receive after an ICMP
port-unreachable, SO_REUSEADDR is not set (it lets another socket take a port
in use there), and ECN is neither read nor set. CI gains a Windows job.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YXLKbmpkRS5DedisNs9VNp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant