The missing everything tool for C and C++

A modern package manager, build system, and build cache in one static binary. Write packages in TOML, not an arcane language, and get reproducible, sandboxed builds that are as fast in CI as on your machine.

Install the latest alpha, then build an example to get started. Sign up for the mailing list for updates, send me an email, or join the Discord server.

curl -fsSL https://spn.spader.zone/install | sh
One binary replaces
  • make
  • cmake
  • conan
  • vcpkg
  • git submodules
  • pkg-config
  • ctest
  • dockerized builds
  • bash + python glue
  • ccache
  • vcvarsall
  • ninja

An extremely fast build system

Write project manifests in TOML, and spn turns them into a build graph and executes it in parallel. You don't have to envy Rust programmers any more.

spn's build executor is as fast as Ninja, but since it owns your entire build, it can aggressively parallelize and cache in ways that other tools simply aren't able to.

It's really, really fast.

spn.toml
[package]
name = "hello"

[[bin]]
name   = "hello"
source = ["main.c"]
$ spn build
Compiled profile debug in 22.5 ms (0 executed, 807 cached)

Reproducible, sandboxed builds

Build scripts are written in the same language as your project. spn sandboxes them by compiling them to WASM modules. Or, if you prefer, write your build scripts in any language that compiles to WASM.

Build scripts are first class programs. They can have their own dependencies, and are only rerun when the files they read change.

build.c
spn_err_t build(spn_t* spn) {
  read_json("endpoints.json");
  generate_code();
  add_to_build("/source/gen/endpoint.c");
}

Zero dependency, single file deployment

spn ships as a single file static executable, or an embeddable library with a C ABI. It runs natively on Linux, macOS, and Windows, supports most common toolchains, and supports your toolchain's cross compilation matrix.

sh
spn build --target x86_64-windows-gnu
spn build --target aarch64-macos
spn build --target x86_64-windows-msvc --toolchain msvc

A package manager built for C and C++

spn includes a sophisticated package manager with first class Git integration. Pick from existing package versions, write your own, or just pin to a commit.

C/C++ are not JS. There isn't a package culture. spn takes great care to provide a package manager that can handle anything from complex dependency structures to hardcoded versions to hobby projects with an excellent developer experience.

spn.toml
[deps.package.imgui]
version = "1.92.8"
options = { sdl3 = true, sdlgpu3 = true, freetype = false }

[patch.imgui]
files = ["patches/oopsie-daisy.patch"]

[deps.build]
yyjson = "0.14.0"

Try out the libraries you already use

Unsure what all of this looks like? Click a library to see how simple it is to use (or even write your own package for) real, complex libraries.

spn.toml
[package]
name = "window"
version = "0.1.0"

[[bin]]
name = "main"
source = ["main.c"]

[deps.package]
sdl3 = "3.4.16"

[config.sdl3]
options = { x11 = true }
SDL3 3.4.16 view on github
[package]
name = "sdl3"
version = "3.4.16"
upstream.url = "https://github.com/libsdl-org/SDL.git"
upstream.commit = "147a8ee32dbf9ac02f3794964490687b6bbda1bc"
system_deps = [
  { lib = "m", when = { os = "linux" } },
  { lib = "dl", when = { os = "linux" } },
  { lib = "pthread", when = { os = "linux" } },
  { lib = "user32", when = { os = "windows" } },
  { lib = "gdi32", when = { os = "windows" } },
  { lib = "winmm", when = { os = "windows" } },
  { lib = "imm32", when = { os = "windows" } },
  { lib = "ole32", when = { os = "windows" } },
  { lib = "oleaut32", when = { os = "windows" } },
  { lib = "version", when = { os = "windows" } },
  { lib = "uuid", when = { os = "windows" } },
  { lib = "advapi32", when = { os = "windows" } },
  { lib = "setupapi", when = { os = "windows" } },
  { lib = "shell32", when = { os = "windows" } },
  { lib = "dinput8", when = { os = "windows" } },
]

[options.x11]
type = "bool"
default = false
public = true
define = "SPN_SDL3_X11"

[options.alsa]
type = "bool"
default = false
public = true
define = "SPN_SDL3_ALSA"

[options.pulseaudio]
type = "bool"
default = false
public = true
define = "SPN_SDL3_PULSEAUDIO"

[options.pipewire]
type = "bool"
default = false
public = true
define = "SPN_SDL3_PIPEWIRE"

[options.oss]
type = "bool"
default = false
public = true
define = "SPN_SDL3_OSS"

[options.dbus]
type = "bool"
default = false
public = true
define = "SPN_SDL3_DBUS"

[options.udev]
type = "bool"
default = false
public = true
define = "SPN_SDL3_UDEV"

[[lib]]
name = "SDL3"
kinds = ["static"]
source = [
  "src/*.c",
  "src/atomic/*.c",
  "src/audio/*.c",
  "src/audio/disk/*.c",
  "src/audio/dummy/*.c",
  "src/camera/*.c",
  "src/camera/dummy/*.c",
  "src/core/*.c",
  "src/cpuinfo/*.c",
  "src/dialog/*.c",
  "src/dynapi/*.c",
  "src/events/*.c",
  "src/filesystem/*.c",
  "src/gpu/*.c",
  "src/haptic/*.c",
  "src/haptic/hidapi/*.c",
  "src/hidapi/*.c",
  "src/io/*.c",
  "src/io/generic/*.c",
  "src/joystick/*.c",
  "src/joystick/hidapi/*.c",
  "src/joystick/virtual/*.c",
  "src/libm/*.c",
  "src/locale/*.c",
  "src/main/*.c",
  "src/main/generic/*.c",
  "src/misc/*.c",
  "src/power/*.c",
  "src/process/*.c",
  "src/render/*.c",
  "src/render/gpu/*.c",
  "src/render/opengl/*.c",
  "src/render/opengles2/*.c",
  "src/render/software/*.c",
  "src/render/vulkan/*.c",
  "src/sensor/*.c",
  "src/sensor/dummy/*.c",
  "src/stdlib/*.c",
  "src/storage/*.c",
  "src/storage/generic/*.c",
  "src/storage/steam/*.c",
  "src/thread/*.c",
  "src/time/*.c",
  "src/timer/*.c",
  "src/tray/*.c",
  "src/video/*.c",
  "src/video/dummy/*.c",
  "src/video/offscreen/*.c",
  "src/video/yuv2rgb/*.c",

  "src/gpu/vulkan/*.c",

  { path = "src/camera/v4l2/*.c", when = { os = "linux" } },
  { path = "src/core/unix/*.c", when = { os = "linux" } },
  { path = "src/core/linux/SDL_evdev.c", when = { os = "linux" } },
  { path = "src/core/linux/SDL_evdev_capabilities.c", when = { os = "linux" } },
  { path = "src/core/linux/SDL_evdev_kbd.c", when = { os = "linux" } },
  { path = "src/core/linux/SDL_threadprio.c", when = { os = "linux" } },
  { path = "src/dialog/unix/*.c", when = { os = "linux" } },
  { path = "src/filesystem/posix/*.c", when = { os = "linux" } },
  { path = "src/filesystem/unix/*.c", when = { os = "linux" } },
  { path = "src/haptic/linux/*.c", when = { os = "linux" } },
  { path = "src/io/io_uring/*.c", when = { os = "linux" } },
  { path = "src/joystick/linux/*.c", when = { os = "linux" } },
  { path = "src/loadso/dlopen/*.c", when = { os = "linux" } },
  { path = "src/locale/unix/*.c", when = { os = "linux" } },
  { path = "src/misc/unix/*.c", when = { os = "linux" } },
  { path = "src/power/linux/*.c", when = { os = "linux" } },
  { path = "src/process/posix/*.c", when = { os = "linux" } },
  { path = "src/thread/pthread/*.c", when = { os = "linux" } },
  { path = "src/time/unix/*.c", when = { os = "linux" } },
  { path = "src/timer/unix/*.c", when = { os = "linux" } },
  { path = "src/tray/unix/*.c", when = { os = "linux" } },

  { path = "src/video/x11/*.c", when = { os = "linux", x11 = true } },
  { path = "src/audio/alsa/*.c", when = { os = "linux", alsa = true } },
  { path = "src/audio/pulseaudio/*.c", when = { os = "linux", pulseaudio = true } },
  { path = "src/audio/pipewire/*.c", when = { os = "linux", pipewire = true } },
  { path = "src/audio/dsp/*.c", when = { os = "linux", oss = true } },
  { path = "src/core/linux/SDL_dbus.c", when = { os = "linux", dbus = true } },
  { path = "src/core/linux/SDL_fcitx.c", when = { os = "linux", dbus = true } },
  { path = "src/core/linux/SDL_ime.c", when = { os = "linux", dbus = true } },
  { path = "src/core/linux/SDL_progressbar.c", when = { os = "linux", dbus = true } },
  { path = "src/core/linux/SDL_system_theme.c", when = { os = "linux", dbus = true } },
  { path = "src/core/linux/SDL_udev.c", when = { os = "linux", udev = true } },

  { path = "src/audio/directsound/*.c", when = { os = "windows" } },
  { path = "src/audio/wasapi/*.c", when = { os = "windows" } },
  { path = "src/camera/mediafoundation/*.c", when = { os = "windows" } },
  { path = "src/core/windows/*.c", when = { os = "windows" } },
  { path = "src/dialog/windows/*.c", when = { os = "windows" } },
  { path = "src/filesystem/windows/*.c", when = { os = "windows" } },
  { path = "src/gpu/d3d12/*.c", when = { os = "windows" } },
  { path = "src/haptic/windows/*.c", when = { os = "windows" } },
  { path = "src/io/windows/*.c", when = { os = "windows" } },
  { path = "src/joystick/windows/*.c", when = { os = "windows" } },
  { path = "src/loadso/windows/*.c", when = { os = "windows" } },
  { path = "src/locale/windows/*.c", when = { os = "windows" } },
  { path = "src/main/windows/*.c", when = { os = "windows" } },
  { path = "src/misc/windows/*.c", when = { os = "windows" } },
  { path = "src/power/windows/*.c", when = { os = "windows" } },
  { path = "src/process/windows/*.c", when = { os = "windows" } },
  { path = "src/render/direct3d/*.c", when = { os = "windows" } },
  { path = "src/render/direct3d11/*.c", when = { os = "windows" } },
  { path = "src/render/direct3d12/*.c", when = { os = "windows" } },
  { path = "src/sensor/windows/*.c", when = { os = "windows" } },
  { path = "src/thread/windows/*.c", when = { os = "windows" } },
  { path = "src/thread/generic/SDL_syscond.c", when = { os = "windows" } },
  { path = "src/thread/generic/SDL_sysrwlock.c", when = { os = "windows" } },
  { path = "src/time/windows/*.c", when = { os = "windows" } },
  { path = "src/timer/windows/*.c", when = { os = "windows" } },
  { path = "src/tray/windows/*.c", when = { os = "windows" } },
  { path = "src/video/windows/*.c", when = { os = "windows" } },
  { path = "src/core/windows/*.cpp", when = { os = "windows" } },
  { path = "src/video/windows/*.cpp", when = { os = "windows" } },
  { path = "src/joystick/gdk/*.cpp", when = { os = "windows" } },

  { path = "src/audio/coreaudio/*.m", when = { os = "macos" } },
  { path = "src/camera/coremedia/*.m", when = { os = "macos" } },
  { path = "src/core/unix/*.c", when = { os = "macos" } },
  { path = "src/dialog/cocoa/*.m", when = { os = "macos" } },
  { path = "src/filesystem/cocoa/*.m", when = { os = "macos" } },
  { path = "src/filesystem/posix/*.c", when = { os = "macos" } },
  { path = "src/gpu/metal/*.m", when = { os = "macos" } },
  { path = "src/haptic/darwin/*.c", when = { os = "macos" } },
  { path = "src/joystick/apple/*.m", when = { os = "macos" } },
  { path = "src/joystick/darwin/*.c", when = { os = "macos" } },
  { path = "src/loadso/dlopen/*.c", when = { os = "macos" } },
  { path = "src/locale/macos/*.m", when = { os = "macos" } },
  { path = "src/misc/macos/*.m", when = { os = "macos" } },
  { path = "src/power/macos/*.c", when = { os = "macos" } },
  { path = "src/process/posix/*.c", when = { os = "macos" } },
  { path = "src/render/metal/*.m", when = { os = "macos" } },
  { path = "src/thread/pthread/*.c", when = { os = "macos" } },
  { path = "src/time/unix/*.c", when = { os = "macos" } },
  { path = "src/timer/unix/*.c", when = { os = "macos" } },
  { path = "src/tray/cocoa/*.m", when = { os = "macos" } },
  { path = "src/video/cocoa/*.m", when = { os = "macos" } },
]
define = [
  { value = "_REENTRANT", when = { os = "linux" } },
  { value = "_THREAD_SAFE", when = { os = "macos" } },
]
flags = [
  "-fno-strict-aliasing",
  "-fvisibility=hidden",
  { value = "-msse", when = { arch = "x86_64" } },
  { value = "-msse2", when = { arch = "x86_64" } },
  { value = "-msse3", when = { arch = "x86_64" } },
  { value = "-fobjc-arc", when = { os = "macos" } },
]

[lib.macos]
frameworks = [
  "AVFoundation",
  "AudioToolbox",
  "Carbon",
  "Cocoa",
  "CoreAudio",
  "CoreFoundation",
  "CoreHaptics",
  "CoreMedia",
  "CoreVideo",
  "ForceFeedback",
  "GameController",
  "IOKit",
  "Metal",
  "QuartzCore",
  "UniformTypeIdentifiers",
]

[[example]]
name = "window"
source = [{ path = "example/window.c", tree = "manifest" }]
deps = ["SDL3"]

[[example]]
name = "gpu"
source = [{ path = "example/gpu.c", tree = "manifest" }]
deps = ["SDL3"]

[profile.default]
options = { x11 = true }
curl -fsSL https://spn.spader.zone/install | sh