@hackage sdl3-bindgen-sys0.0.0.2
Complete SDL3 bindings, raw + curated, generated by hs-bindgen
Categories
License
BSD-3-Clause
Maintainer
jeremy@jeremy-nuttall.com
Links
Versions
Installation
Tested Compilers
Dependencies (15)
- base >=4.17 && <4.23
- sdl3-bindgen-sys Show all…
Dependents (0)
Package Flags
abi-assertions
(on by default)
Verify the baked ABI layout against the system SDL3 headers at build time via generated C static assertions (disable only to diagnose)
optimize
(on by default)
Build with -O2. Package ghc-options win over cabal's optimization setting, so use -f -optimize for faster iterative builds of this large package.
optimize-aggressively
(off by default)
Build with expensive optimizations. Consider this the release build: slow, but paid once if caching is set up, so it may be worth it for artifacts you intend to ship.
Currently: -O2 -fexpose-all-unfoldings -flate-specialise -flate-dmd-anal -fstg-lift-lams.
strict
(off by default)
EXPERIMENTAL: compile the generated modules with Strict.
The emitted hs-bindgen code has not been audited for laziness dependence; main library only.
NB: Implies StrictData (GHC semantics), so -f -strict-data does not undo strict fields.
strict-data
(on by default)
Compile the generated modules with StrictData (strict fields on every generated record). Main library only; the vendored runtime keeps its upstream semantics. Disable if you need lazy fields.
sdl3-bindgen-sys
Fully automated, luxury low-level Haskell bindings to SDL3:
the whole SDL 3.4 API, machine-generated from the headers using an
ever-so-slightly hacked version of hs-bindgen.
This package gets you SDL3 in full — windowing, input, audio, and the newfangled GPU API — today, if you dare.
CI runs against 64-bit Linux, macOS, and Windows, which is what this package aims to support.
This library aims to be:
- Complete by construction: Generated from all 58 headers of the SDL 3.4 API (291 modules), so a gap is either a code generation bug or a deliberate omission rather than a binding waiting to be hand-written.
- Curated: The
SDL3.Sys.*layer wrapshs-bindgen's output with best-effort Haskell casing, native scalar types, and FFI safety decisions and recommendations. - First-class SDL docs: Every binding carries SDL's header documentation, and notes from the code generator's curation layer.
- ABI-verified: A generated translation unit of C
_Static_asserts verifies the library's baked layouts against your SDL at every build — divergence is a compile error naming the declaration, not memory corruption.
Quick start
Install build requirements
Install SDL >= 3.2 development files where pkg-config can find
them. The development headers must be present, not just the shared
library.
Common setups:
- Debian/Ubuntu:
apt install libsdl3-dev - macOS:
brew install sdl3 - Arch:
pacman -S sdl3 - Fedora:
dnf install SDL3-devel - Windows: WSL2 with the Linux instructions, or native MSYS2. See Windows set up
Set up your project
- Add
sdl3-bindgen-systobuild-depends - Replace the contents of
Main.hswith:
{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE BlockArguments #-}
import Control.Monad (unless)
import Foreign.C.ConstPtr (ConstPtr (..))
import Foreign.C.String (peekCString, withCString)
import SDL3.Sys qualified as SDL3
main :: IO ()
main = do
ok <- SDL3.init SDL3.SDL_INIT_VIDEO
unless ok do
err <- peekCString . unConstPtr =<< SDL3.getError
fail ("SDL_Init: " <> err)
window <- withCString "hello" \title ->
SDL3.createWindow (ConstPtr title) 640 480 0
SDL3.delaySafe 2000
SDL3.destroyWindow window
SDL3.quit
For more examples and templates, see
lithon-examples
in the repository:
sdl3-rawis a minimal triangle with an event loopshmupis a playableapecsgame running on and rendering through these bindings
Windows set up
There are two ways to set this up that I am aware of. In order of convenience:
WSL2
The Linux instructions apply unchanged. Under WSLg an SDL window displays like any Linux app.
Native (MSYS2)
Install build dependencies:
pacman -Syyu # repeat/restart terminal if pacman asks you to
pacman -S mingw-w64-ucrt-x86_64-sdl3 mingw-w64-ucrt-x86_64-pkgconf
[!NOTE] The UCRT64 pkgconf is required. MSYS2
pkg-configreports POSIX-style paths that GHC can't use on Windows.
Stack users
[!IMPORTANT] Stack users need some additional setup.
Adjust the library version in
extra-depsto your desired target.
- Run the
pacmancommands above throughstack exec -- pacman ...so that the packages are installed instack's MSYS2. - Add
msys-environment: UCRT64to yourstack.yaml. - Add
sdl3-bindgen-sys-0.0.0.2toextra-depsin yourstack.yaml. Runningstack buildshould print out a helpful, pasteable entry for this purpose.
Your stack.yaml should look something like this:
snapshot: lts-24.51
packages:
- .
extra-deps:
- sdl3-bindgen-sys-0.0.0.2 # hash may be here if you copy from stack build
msys-environment: UCRT64 # important: build will not work without this
Library structure
For most uses, you will import SDL3.Sys qualified as SDL3.
SDL3.Sys re-exports one module per SDL header.
The raw hs-bindgen output lives underneath as SDL3.Sys.Bindgen.*, if
you need to drop down to C types.
Safe and unsafe FFI
Most functions come in both FFI flavors: createWindow is an unsafe
foreign import; createWindowSafe is the safe one.
General rules for safe vs. unsafe FFI:
- You must use a
safecall if C will call back into Haskell. - You should use a
safecall if the C call could take a while (e.g., waiting on some OS event, or a locking mechanism, etc.). - You should use an
unsafecall if the C call is fast;unsafecalls block the current GHC thread (capability) and the garbage collector, but their overhead is very low compared tosafecalls.
Typed constants
SDL declares its flag and constant vocabularies as typedef UintN
plus #defines, an association C never states, so binding generators
cannot recover it.
The curated layer restores this information from an explicit registry maintained alongside the generator.
Similar to the vulkan library, every group member is a pattern synonym
typed at its newtype, e.g. SDL_INIT_VIDEO :: SDL_InitFlags.
You can combine bitmask groups with .|. from Data.Bits:
SDL3.init (SDL3.SDL_INIT_VIDEO .|. SDL3.SDL_INIT_AUDIO)
Conversion to and from C types
SDL3.Sys re-exports SDL3.Sys.Runtime, the conversion vocabulary
you'll actually reach for: toBool/fromBool for C-typed struct
fields (e.g. a keyboard event's repeat), and the CEnum classes for
moving between enum newtypes and their integral representations.
Platform support
64-bit platforms only. Linux, macOS (aarch64, Homebrew sdl3), and
Windows (MSYS2 UCRT64, including the LLP64 layouts) are all targets,
and CI builds the released package on all three. 32-bit targets are
rejected by the ABI assertions — 64-bit layouts are baked in.
Common issues
- Blank screen or crash on macOS — SDL's Cocoa backend requires
video and event calls on the process main thread. Keep the SDL
loop on
main(don'tforkIOit);runOnMainThreadSafeis bound for marshalling work onto it. initfails on Windows — the bindings are generated withSDL_MAIN_HANDLED: callsetMainReadybeforeinit.fooorfooSafe? — every function's haddock states its flavor choice, and the rationale, under itssdl3-bindgen-sysnotes section.- Branching on
SDL3.Sys.PlatformDefines— don't: its two constants (sDL_PLATFORM_LINUX,sDL_PLATFORM_UNIX) are baked to the generation host's value of1on every platform. setLinuxThreadPriority(AndPolicy)off-Linux — both exist everywhere but fail with anSDL_GetErrormessage.
What is not bound
Known gaps, so you can discover them here instead of mid-build:
- Variadic functions — hs-bindgen skips them. That means the
SDL_Logfamily (including theV-suffixedva_listvariants),SDL_SetError, andSDL_RenderDebugTextFormat(the fixed-stringSDL_RenderDebugTextis bound). For logging, format in Haskell first and write a one-line"%s"C shim if you need SDL's log routing; forSDL_SetErrorthere is currently no workaround in this package. - Function-like macros — no linkable symbol exists. Macro constants are bound; see Typed constants.
- The seven
long-typedSDL_stdinc.hlibc clones (strtol/ltoafamilies,lround/lroundf): their FFI types cannot be correct on both LP64 and LLP64, so they are omitted. - Three Windows-only interop functions (
SDL_SetWindowsMessageHook,SDL_GetDirect3D9AdapterIndex,SDL_GetDXGIOutputInfo) — niche; native window handles are reached through the boundSDL_GetWindowPropertieskeys instead.
Versioning
The 0.0.x series is experimental: pin to the minor
(e.g., >=0.0.0.1 && <0.0.1) and expect surface-shaping changes.
SDL >= 3.2.0 is required; the surface is generated from 3.4.2.
Declarations newer than your SDL still compile and link — their wrapper
C is gated on SDL's own version macros, so calling one on an older SDL
fails at the call site via SDL_GetError (exactly like the Linux-only
functions off Linux). The wrapper gates and the ABI assertion layer are
driven by an empirically verified availability registry rather than
SDL's (occasionally wrong) \since annotations; a handful of haddock
@since lines therefore repeat an upstream floor the registry
corrects — where they disagree, the registry wins, and a gated call's
SDL_GetError message states the true floor.
Two semantic deltas to know when running against a 3.2-series SDL:
SDL_COLORSPACE_YUV_DEFAULTis baked at its 3.4 value (BT601_LIMITED); 3.2 defined it asJPEG.- Below SDL 3.2.12,
SDL_MouseWheelEvent.integer_x/integer_yread bytes SDL never wrote — memory-safe (SDL_Eventis 128 bytes), but meaningless.
Known documentation issues
- A few module overviews absorb the opening of the first declaration's documentation. Seems to be upstream — Doxygen fuses SDL's file-level category comments before any other tool sees them in these cases.
- Cross-header references in the raw
SDL3.Sys.Bindgen.*docs may appear as plain text; the curatedSDL3.Sys.*modules should contain repaired links.
Provenance and licensing
Generated by hs-bindgen
driven by the repository's lithon-codegen, from the SDL 3.4.2
headers. The generated tree is never hand-edited, but bugs are mine, not
SDL's: report them at the
issue tracker.
sdl3-bindgen-sysis BSD-3-Clause (seeLICENSE).- The SDL header documentation embedded in the haddocks is covered by SDL's
zlib license (
LICENSE_SDL). - The vendored hs-bindgen and c-expr runtimes are BSD-3-Clause, (c) Well-Typed LLP
and Anduril Industries (
LICENSE_hs-bindgen-runtime,LICENSE_c-expr-runtime).