Zig bindings for SDL libs.
  • C 90.6%
  • Zig 4.7%
  • C++ 4.1%
  • CMake 0.4%
  • Objective-C 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-11-02 21:01:20 +00:00
.github/workflows Update to Zig 0.17.0 2026-10-24 22:38:58 +01:00
libs [Breaking] Update SDL3 headers and bindings to 3.2.26 2025-11-14 02:58:13 +00:00
src Make sdl3.Keymod enum non-exhaustive (#38) 2026-11-02 21:01:20 +00:00
.gitignore build: Upgrade to Zig 0.16 (#31) 2026-04-22 22:17:56 +01:00
build.zig Update to Zig 0.17.0 2026-10-24 22:38:58 +01:00
build.zig.zon Update to Zig 0.17.0 2026-10-24 22:38:58 +01:00
LICENSE files from monorepo @ bde42aaeec763c1bd8781d26285b0f4dc65b1a4c 2024-11-04 21:36:24 +00:00
README.md Update README. Also deprecate prebuilt libs 2026-05-11 23:24:15 +01:00

zsdl

Zigified bindings for SDL libs. Work in progress.

Getting started (SDL2)

Example build.zig:

pub fn build(b: *std.Build) !void {

    const exe = b.addExecutable(.{ ... });
    exe.linkLibC();

    const zsdl = b.dependency("zsdl", .{});

    exe.root_module.addImport("zsdl2", zsdl.module("zsdl2"));
    exe.root_module.addImport("zsdl2_ttf", zsdl.module("zsdl2_ttf"));
    exe.root_module.addImport("zsdl2_image", zsdl.module("zsdl2_image"));

    // Link against SDL libs
    linkSdlLibs(exe);
}

Link against SDL:

pub fn linkSdlLibs(compile_step: *std.Build.Step.Compile) void {
    // Adjust as needed for the libraries you are using.
    switch (compile_step.rootModuleTarget().os.tag) {
        .windows => {
            compile_step.root_module.linkSystemLibrary("SDL2", .{});
            compile_step.root_module.linkSystemLibrary("SDL2main", .{}); // Only needed for SDL2, not ttf or image
            compile_step.root_module.linkSystemLibrary("SDL2_ttf", .{});
            compile_step.root_module.linkSystemLibrary("SDL2_image", .{});
        },
        .linux => {
            compile_step.root_module.linkSystemLibrary("SDL2", .{});
            compile_step.root_module.linkSystemLibrary("SDL2_ttf", .{});
            compile_step.root_module.linkSystemLibrary("SDL2_image", .{});
        },
        .macos => {
            compile_step.root_module.linkFramework("SDL2", .{});
            compile_step.root_module.linkFramework("SDL2_ttf", .{});
            compile_step.root_module.linkFramework("SDL2_image", .{});
        },
        else => {},
    }
}

Using prebuilt libraries

To use the prebuilt libraries, add the following to your build.zig:

pub fn build(b: *std.Build) !void {

    // ... other build steps ...

    // Use prebuilt libs instead of relying on system-installed SDL.
    @import("zsdl").prebuilt_sdl2.addLibraryPathsTo(exe);
    if (@import("zsdl").prebuilt_sdl2.install(b, target.result, .bin, .{
        .ttf = true,
        .image = true,
    })) |install_sdl2_step| {
        b.getInstallStep().dependOn(install_sdl2_step);
    }

    // Prebuilt libraries are installed to the executable directory. Set the RPath so the
    // executable knows where to look at runtime.
    switch (exe.rootModuleTarget().os.tag) {
        .windows => {}, // rpath is not used on Windows
        .linux => exe.root_module.addRPathSpecial("$ORIGIN"),
        .macos => exe.root_module.addRPathSpecial("@executable_path"),
        else => {},
    }
}

Using zsdl2 in your code

const std = @import("std");
const sdl = @import("zsdl2");

pub fn main() !void {
    ...
    try sdl.init(.{ .audio = true, .video = true });
    defer sdl.quit();

    const window = try sdl.Window.create(
        "zig-gamedev-window",
        sdl.Window.pos_undefined,
        sdl.Window.pos_undefined,
        600,
        600,
        .{ .opengl = true, .allow_highdpi = true },
    );
    defer window.destroy();
    ...
}

Getting started (SDL3)

TODO: Document SDL3 bindings usage