← ziglang.inraylib-zigGitHub

This page is raylib-zig's own compatibility record, docs/compatibility.md, shown as it was when this site was built.

Compatibility with C raylib — what is verified, and how

Status as of 2026-10-16 (tag raylib-6.2-parity and later). This records how compatible the Zig port is with upstream C raylib, the evidence behind each claim, and — just as important — what is not covered.

Short answer: for the pinned configuration (raylib 6.2, Linux x86-64, desktop GLFW, OpenGL 3.3, default config.h), the Zig library is a drop-in replacement for C raylib: unmodified raylib programs compile against the same raylib.h, link against the Zig library, and render byte-identical frames for every upstream example that can be run deterministically (217 of 217), with numeric, audio and data functions bit-exact on their test grids. Outside that configuration, compatibility is not claimed.

1. Scope: the configuration the claims apply to

Axis Supported / verified Not supported (yet)
raylib version 6.2 (tag 6.2, git 02566453) other versions (re-port per release; 6.1-dev → 6.2 took one session)
OS / arch Linux x86-64 others untested
Platform backend PLATFORM_DESKTOP_GLFW (GLFW 3, X11) SDL, RGFW, Win32, DRM, Android (see not-migrated.md)
Graphics API GRAPHICS_API_OPENGL_33 OpenGL 1.1 / 2.1 / 4.3, ES2, rlsw
Web (in progress) PLATFORM_WEB + GRAPHICS_API_OPENGL_ES3 (WebGL 2) on wasm32-emscripten: ported; the browser gate covers 209 examples (every desktop-gated example but 8; exclusions, one known web gap and what audio covers in web.md) (see web.md) claims above do not yet extend to the web
Feature config raylib’s default config.h any non-default SUPPORT_* flag (see §5)
Library form static libraylib.a shared libraylib.so (not built)
Optimization Debug and ReleaseFast (both gated, §3) —
Property Result Evidence
Public API symbols 619 / 619 RLAPI functions in raylib.h exported, each defined exactly once, all from Zig objects (none from C) nm sweep of libraylib.a vs raylib.h prototypes
Header programs compile against the unmodified upstream raylib.h (plus raymath.h, rlgl.h, rcamera.h) 219 upstream examples build unmodified
raymath / rlgl / rcamera out-of-line exported symbols (RMAPI/RLAPI) math/camera grids link against the Zig exports
Mirrored constants 514 enum values / #defines (numeric, string, bool flags) in the Zig sources equal raylib’s python3 tools/constaudit.py (0 mismatches; negative control re-finds the historical SHADER_LOC off-by-one)
Struct layout & by-value ABI Color/Vector*/Rectangle/Matrix/Image/Model… passed by value and by pointer exactly as C does exercised by every gate below; the separate Zig API’s 35 structs are checked field-by-field against translate-c’d raylib.h (zig build apitest)
Global state CoreData/rlglData unchanged between 6.1-dev and 6.2; internal to Zig modules struct diff of upstream headers

3. Behavioral compatibility (does it do the same thing?)

The oracle is the same build of upstream C raylib (all-C library from the vendored 6.2 sources), compiled side by side; every gate compares C output to Zig output byte-for-byte — no tolerances.

Gate What is compared Result
zig build test 12 scenes (2D, text, textures, image ops, 3D shapes/meshes) rendered headless under mesa llvmpipe 12/12 framebuffers identical
tools/exdiff.sh (examples) every upstream example (unmodified), final frame after 240 frames, deterministic shim (fixed clock, hidden window, fixed RNG seed) 217/217 automated identical; 10 excluded (§4) = all 227 accounted for
zig build mathtest 148 raymath functions over a pseudo-random grid incl. edge cases (opposite vectors, TRS round-trips, cubic Hermite) 93,000 values bit-identical
zig build camtest / gesttest rcamera functions over an input grid / rgestures over scripted touch events 7,500 / 3,200 values bit-identical
zig build audiocheck decoded PCM (WAV/OGG/MP3/QOA/XM/MOD), Wave ops, export round-trips, stream/music metadata 43/43 identical
zig build datacheck compression, base64, file/data helpers 0 failures
zig build cdiff paths examples can’t reach, 12 programs: Text* and font loading (TTF/BMFont/image fonts, crafted .fnt files, ExportFontAsCode), hashes for lengths 0..200, path predicates, file system I/O on a real file tree, the automation events file (glibc fgets/sscanf edge cases), image ops across all 13 formats plus export/load, every model format and animation plus ExportMesh/AsCode and GenMesh*, wave export/format/crop, rlgl batches/shaders/readback, rshapes point lists and a 720-frame thickness/angle sweep; every TraceLog line compared 12/12 programs identical (Debug and ReleaseFast)
Real GPU spot check (EXDIFF_GPU=1) examples on Intel Iris Xe (Mesa 25.2.8, GL 4.6) instead of llvmpipe 219/219 identical (run before the last two audio exclusions)
ReleaseFast all non-example gates at -Doptimize=ReleaseFast pixel 12/12, math, cam, gest, data, audio 43/43, cdiff 4/4 identical
ReleaseFast examples sweep full examples gate, optimized Zig library vs optimized C oracle 217/217 identical

Upstream behavior is reproduced including its quirks: e.g. ImageDrawTextPro is an empty stub in 6.2 and is a no-op here too; upstream example bugs are kept where they affect output.

4. What the oracle cannot see

These are limits of the evidence, not known incompatibilities:

5. Known incompatibilities

Area Detail
Non-default config.h The Zig modules implement raylib’s default feature set. Code behind default-off flags is not ported: image formats TGA, JPG, PSD, HDR, PIC, PNM, KTX, ASTC, PKM, PVR, PEP; font format BDF; audio format FLAC; rshapes’ triangles fallback (SUPPORT_QUADS_DRAW_MODE=0). Rebuilding with different SUPPORT_* values changes the C oracle but not the Zig port.
Other platforms / GL versions Not compiled (see §1, not-migrated.md).
Shared library Only a static archive is built.
File system misuse Where C raylib’s result depends on undefined behaviour or on the filesystem, the Zig port picks one documented answer: LoadFileText on a directory returns NULL (“Failed to read text file”); C’s answer varies by filesystem (on ext4 it returns “”). LoadFileData/GetFileLength on a directory match C on ext4. ExportDataAsCode with dataSize <= 0 returns false (C reads data[-1]). NULL paths return NULL/false/0 where C would crash, and SaveFileText(f, NULL) writes an empty file (glibc writes “(null)”). A failed write makes SaveFileData/SaveFileText return false. LoadDirectoryFilesEx with no matches returns paths == NULL (C returns a calloc(0) pointer); count is 0 either way and UnloadDirectoryFiles accepts both.
Multi-page BMFont raylib 6.2 unloads atlas pages 1..n before drawing them into the merged atlas (rtext.c lines 2714/2727: a use-after-free, so its pixels are undefined). The port draws the pages, then unloads them. Page metadata is gated; the merged pixels can’t be.
Other misuse and allocation failure Where C crashes or reads out of bounds the port returns raylib’s failure result instead: a NULL file type in LoadWaveFromMemory, ExportImageAsCode/ExportWaveAsCode on empty data, NULL text arguments to Text* functions, malformed IQM/glTF offsets (read as zeros), negative GenImage* sizes, a failed allocation (logs a warning; raylib has no wording for it). rlGetShaderLocsDefault() after rlglClose returns NULL (C returns freed memory). LoadImageColors on a compressed format returns zeroed memory (C: uninitialized).

There are no known behavioral differences for valid inputs within the configuration of §1.

6. The idiomatic Zig API (a separate surface)

@import("raylib") is not ABI-compatible by design — it is a Zig API over the C ABI above, with raylib’s names and design (docs/zig-api.md). Its compatibility is checked differently:

Re-verifying

zig build && zig build test mathtest camtest gesttest datacheck audiocheck cdiff apitest
python3 tools/constaudit.py
tools/exdiff.sh "$(find ~/.cache/zig-local -name libraylib_oracle.a | head -1)" zig-out/lib/libraylib.a
zig build apiexamples

Run the examples sweeps on a quiet machine: the audio-driven examples are timing-sensitive under heavy CPU load.