A Zig package that provides you with the means to link SDL2 to your project, as well as a Zig-infused header implementation (allows you to not have the SDL2 headers on your system and still compile for SDL2) and a shallow wrapper around the SDL apis that allow a more Zig-style coding with Zig error handling and tagged unions.
This is an example build.zig that will link the SDL2 library to your project.
conststd=@import("std");
constsdl=@import("sdl"); // Replace with the actual name in your build.zig.zonpubfnbuild(b: *std.Build) !void {
// Determine compilation targetconsttarget=b.standardTargetOptions(.{});
constoptimize=b.standardOptimizeOption(.{});
// Create a new instance of the SDL2 Sdk// Specify dependency name explicitly if necessary (use sdl by default)constsdk=sdl.init(b, .{});
// Create executable for our exampleconstroot_module=b.createModule(.{
.root_source_file=b.path("my-game.zig"),
.target=target,
.optimize=optimize,
});
constdemo_basic=b.addExecutable(.{
.name="demo-basic",
.root_module=root_module,
});
sdk.link(demo_basic, .dynamic, sdl.Library.SDL2); // link SDL2 as a shared library// Add "sdl2" package that exposes the SDL2 api (like SDL_Init or SDL_CreateWindow)root_module.addImport("sdl2", sdk.getNativeModule());
// Install the executable into the prefix when invoking "zig build"b.installArtifact(demo_basic);
}This package exposes the SDL2 API as defined in the SDL headers. Use this to create a normal SDL2 program:
conststd=@import("std");
constSDL=@import("sdl2"); // Add this package by using sdk.getNativeModulepubfnmain() !void {
if (SDL.SDL_Init(SDL.SDL_INIT_VIDEO|SDL.SDL_INIT_EVENTS|SDL.SDL_INIT_AUDIO) <0)
sdlPanic();
deferSDL.SDL_Quit();
varwindow=SDL.SDL_CreateWindow(
"SDL2 Native Demo",
SDL.SDL_WINDOWPOS_CENTERED, SDL.SDL_WINDOWPOS_CENTERED,
640, 480,
SDL.SDL_WINDOW_SHOWN,
) orelsesdlPanic();
defer_=SDL.SDL_DestroyWindow(window);
varrenderer=SDL.SDL_CreateRenderer(window, -1, SDL.SDL_RENDERER_ACCELERATED) orelsesdlPanic();
defer_=SDL.SDL_DestroyRenderer(renderer);
mainLoop: while (true) {
varev: SDL.SDL_Event=undefined;
while (SDL.SDL_PollEvent(&ev) !=0) {
if(ev.type==SDL.SDL_QUIT)
break :mainLoop;
}
_=SDL.SDL_SetRenderDrawColor(renderer, 0xF7, 0xA4, 0x1D, 0xFF);
_=SDL.SDL_RenderClear(renderer);
SDL.SDL_RenderPresent(renderer);
}
}
fnsdlPanic() noreturn {
conststr=@as(?[*:0]constu8, SDL.SDL_GetError()) orelse"unknown error";
@panic(std.mem.sliceTo(str, 0));
}This package also exposes the SDL2 API with a more Zig-style API. Use this if you want a more convenient Zig experience.
Note: This API is experimental and might change in the future
conststd=@import("std");
constSDL=@import("sdl2"); // Created in build.zig by using exe.root_module.addImport("sdl2", sdk.getWrapperModule());pubfnmain() !void {
trySDL.init(.{
.video=true,
.events=true,
.audio=true,
});
deferSDL.quit();
varwindow=trySDL.createWindow(
"SDL2 Wrapper Demo",
.{ .centered= {} }, .{ .centered= {} },
640, 480,
.{ .vis=.shown },
);
deferwindow.destroy();
varrenderer=trySDL.createRenderer(window, null, .{ .accelerated=true });
deferrenderer.destroy();
mainLoop: while (true) {
while (SDL.pollEvent()) |ev| {
switch (ev) {
.quit=>break :mainLoop,
else=> {},
}
}
tryrenderer.setColorRGB(0xF7, 0xA4, 0x1D);
tryrenderer.clear();
renderer.present();
}
}/// Just call `Sdk.init(b, .{})` to obtain a handle to the Sdk!/// Use `sdl` as dependency name by default.constSdk=@This();
/// Creates a instance of the Sdk and initializes internal steps./// Initialize once, use everywhere (in your `build` function).////// const SdkOption = struct {/// dep_name: ?[]const u8 = "sdl",/// maybe_config_path: ?[]const u8 = null,/// maybe_sdl_ttf_config_path: ?[]const u8 = null,/// };pubfninit(b: *Build, opt: SdkOption) *Sdk/// Returns a module with the raw SDL api with proper argument types, but no functional/logical changes/// for a more *ziggy* feeling./// This is similar to the *C import* result.pubfngetNativeModule(sdk: *Sdk) *Build.Module;
/// Returns a module with the raw SDL api with proper argument types, but no functional/logical changes/// for a more *ziggy* feeling, with Vulkan support! The Vulkan module provided by `vulkan-zig` must be/// provided as an argument./// This is similar to the *C import* result.pubfngetNativeModuleVulkan(sdk: *Sdk, vulkan: *Build.Module) *Build.Module;
/// Returns the smart wrapper for the SDL api. Contains convenient zig types, tagged unions and so on.pubfngetWrapperModule(sdk: *Sdk) *Build.Module;
/// Returns the smart wrapper with Vulkan support. The Vulkan module provided by `vulkan-zig` must be/// provided as an argument.pubfngetWrapperModuleVulkan(sdk: *Sdk, vulkan: *Build.Module) *Build.Module;
/// Links SDL2 or SDL2_ttf to the given exe and adds required installs if necessary./// **Important:** The target of the `exe` must already be set, otherwise the Sdk will do the wrong thing!pubfnlink(sdk: *Sdk, exe: *Build.Step.Compile, linkage: std.builtin.LinkMode, comptimelibrary: Library) void;All of those are dependencies for the target platform, not for your host. Zig will run/build the same on all source platforms.
For Windows, you need to fetch the correct dev libraries from the SDL download page. It is recommended to use the MinGW versions if you don't require MSVC compatibility.
Right now, cross-compiling for MacOS isn't possible. On a Mac, install SDL2 via brew.
If you are cross-compiling, no dependencies exist. The build Sdk compiles a libSDL2.so stub which is used for linking.
If you compile to your target platform, you require SDL2 to be installed via your OS package manager.
This project tries to provide you the best possible development experience for SDL2. Thus, this project supports the maximum amount of cross-compilation targets for SDL2.
The following table documents this. The rows document the target whereas the columns are the build host:
| Windows (x86_64) | Windows (i386) | Linux (x86_64) | MacOS (x86_64) | MacOS (aarch64) | |
|---|---|---|---|---|---|
i386-windows-gnu | ✅ | ✅ | ✅ | ✅ | |
i386-windows-msvc | ✅ | ✅ | ✅ | ✅ | |
x86_64-windows-gnu | ✅ | ✅ | ✅ | ✅ | |
x86_64-windows-msvc | ✅ | ✅ | ✅ | ✅ | |
x86_64-macos | ❌ | ❌ | ❌ | ✅ | ❌ |
aarch64-macos | ❌ | ❌ | ❌ | ❌ | |
x86_64-linux-gnu | 🧪 | 🧪 | ✅ | 🧪 | |
aarch64-linux-gnu | 🧪 | 🧪 | 🧪 | 🧪 |
Legend:
- ✅ Cross-compilation is known to work and tested via CI
- 🧪 Experimental cross-compilation support, covered via CI
⚠️ Cross-compilation might work, but is not tested via CI- ❌ Cross-compilation is not possible right now
You can contribute to this project in several ways:
- Use it! This helps me to track bugs (which i know that there are some), and usability defects (which we can resolve then). I want this library to have the best development experience possible.
- Implement/improve the linking experience: Right now, it's not possible to cross-compile for MacOS, which is very sad. We might find a way to do so, though! Also VCPKG is not well supported on windows platforms.
- Improve the wrapper. Just add the functions you need and make a PR. Or improve existing ones. I won't do it for you, so you have to get your own hands dirty!