slay

package module
v1.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 26, 2026 License: BSD-3-Clause Imports: 16 Imported by: 0

README

Slay

CI Standard License

Zero-configuration build tool for C and C++ projects.

Have you ever had a single main.cpp file that you just want to compile, without having to make sure the order of flags are correct and ideally without having to provide any flags at all?

Slay (or slay for short) handles compiler detection, flag ordering, library discovery via pkg-config, testing, formatting, cross-compilation, etc., without a single configuration file.

It should be possible to compile all of the examples in the examples directory, simply by running slay in each directory, as long as the right packages and libraries have been installed.

This is a Go port of xyproto/cxx (which does approximately the same, but uses Python + Scons instead).

Quick Start

slay              # build the project
slay run          # build and run
slay clean        # remove built files

No configuration files are needed, but the project needs to either be very simple (a single main.cpp) or have an slay-friendly directory structure.

The auto-detection of external libraries and headers relies on them being included in the main source file.

Badge

If you like, you can add this shield to your project to indicate that it can be compiled without any particular build-related configuration:

Compiles with Slay

Just make sure that it builds with slay first, then add this to your README.md:

[![Compiles with Slay](https://img.shields.io/badge/Compiles_with-Slay-2fc298)](https://github.com/xyproto/slay)

It is also possible to add it to the list of projects that compiles with Slay.

Installation

Arch Linux

git clone https://github.com/xyproto/slay
cd slay
make
sudo make install

Other Linux distros, FreeBSD, NetBSD, macOS

git clone https://github.com/xyproto/slay
cd slay
make
sudo make install    # use gmake on BSD

Windows (MSYS2)

git clone https://github.com/xyproto/slay
cd slay
make
make install

Or with go install:

go install github.com/xyproto/slay/cmd/slay@latest
sudo ln -sf ~/go/bin/slay /usr/local/bin/slay

All Commands

Slay uses a composable command syntax: combine modifiers with an action.

Modifiers (combinable)

clang       use clang/clang++ compiler
zap         use zapcc++ compiler
debug       enable debug flags and sanitizers
nosan       disable sanitizers (use with debug)
opt         enable optimizations (-Ofast/-O3, -flto)
strict      enable strict warning flags
sloppy      enable permissive flags
small       optimize for size (-Os)
tiny        minimize size (-Os + sstrip/upx)
win64       cross-compile for 64-bit Windows

Actions

build       compile the project (default)
run         build and run
debug       debug build and launch debugger
rebuild     clean and build
clean       remove built files
fastclean   only remove executable and *.o
test        build and run tests
testbuild   build tests (without running)
pgo         profile-guided optimization (build, run, rebuild)
fmt         format source code with clang-format
generate    generate CMakeLists.txt
makefile    generate a standalone Makefile
cmake       build with cmake (prefers ninja, falls back to make)
make        build with make (falls back to cmake+make)
ninja       build with ninja (falls back to cmake+ninja)
install     install the project (PREFIX, DESTDIR)
pkg         package the project into pkg/
export      export a standalone Makefile and build.sh
script      generate build.sh and clean.sh
valgrind    build and profile with valgrind
pro         generate QtCreator project file
version     show version

Compound actions

ninjainstall  install from ninja build
ninjaclean    clean ninja build
makeinstall   install from make/cmake+make build
makeclean     clean make/cmake+make build

Examples

slay                    # standard build
slay clang              # build with clang
slay clang strict       # build with clang and strict warnings
slay debug              # debug build and launch debugger
slay debug build        # debug build (without launching debugger)
slay clang debug        # clang debug build and launch debugger
slay opt run            # optimized build and run
slay small win64        # size-optimized cross-compile for Windows
slay -C <dir> ...      # run in the given directory

Legacy compound commands (debugbuild, clangstrict, smallwin64, etc.) are still accepted.

Example Use

Create a main.cpp file:

#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <ostream>
#include <string>

using namespace std::string_literals;

class Point {
public:
    double x;
    double y;
    double z;
};

std::ostream& operator<<(std::ostream& output, const Point& p)
{
    using std::setfill;
    using std::setw;
    output << "{ "s << setfill(' ') << setw(3) << p.x << ", "s << setfill(' ') << setw(3) << p.y
           << ", "s << setfill(' ') << setw(3) << p.z << " }"s;
    return output;
}

Point operator+(const Point& a, const Point& b)
{
    return Point { .x = a.x + b.x, .y = a.y + b.y, .z = a.z + b.z };
}

Point operator*(const Point& a, const Point& b)
{
    return Point { .x = a.x * b.x, .y = a.y * b.y, .z = a.z * b.z };
}

int main(int argc, char** argv)
{
    Point p1 { .x = 1, .y = 2, .z = 3 };
    Point p2 { .y = 42 };

    using std::cout;
    using std::endl;

    cout << "     p1 = " << p1 << endl;
    cout << "     p2 = " << p2 << endl;
    cout << "p1 + p2 = " << p1 + p2 << endl;
    cout << "p1 * p2 = " << p1 * p2 << endl;

    return EXIT_SUCCESS;
}

Then build and run:

slay run

Rebuild from scratch:

slay rebuild

Build with profile-guided optimization:

slay pgo    # builds, runs (collecting profiling data), then rebuilds with PGO
slay        # subsequent builds use the profiling data

Directory Structure

myproject/
├── main.cpp              # main source (or main.cc, main.c)
├── include/              # project headers (.h, .hpp)
│   └── hello.h
├── common/               # shared source files
│   ├── hello.cpp
│   └── hello_test.cpp    # test file (must contain main())
├── img/                  # images
├── shaders/              # shaders
├── data/                 # data files
├── share/                # shared data files (or shared/)
└── scripts/              # script files
  • The main source file can live in the project root or src/.
  • The executable name matches the parent directory name.
  • Files ending with _test.* are compiled separately by slay test.
  • include/ and common/ can also be at ../include and ../common.

Defines

These defines are passed to the compiler, with paths that work both during development and after installation:

Define Development Installed
DATADIR ./data or ../data $PREFIX/share/$app/data
IMGDIR ./img or ../img $PREFIX/share/$app/img
SHADERDIR ./shaders or ../shaders $PREFIX/share/$app/shaders
SHAREDIR ./share or ../share $PREFIX/share/$app
RESOURCEDIR ./resources or ../resources $PREFIX/share/$app/resources
RESDIR ./res or ../res $PREFIX/share/$app/res
SCRIPTDIR ./scripts or ../scripts $PREFIX/share/$app/scripts

See examples/sdl2, examples/win64crate (uses IMGDIR) and examples/mixer (uses RESOURCEDIR).

Testing

  • Source files can have corresponding _test files (e.g. quaternions.ccquaternions_test.cc).
  • Each _test.* file must contain its own main function.
  • Run with slay test.

Library Auto-Detection

Slay auto-detects libraries from #include directives in your source files using pkg-config. Supported libraries include:

  • Graphics: OpenGL, GLUT, GLFW, GLEW, GLM, Vulkan, SDL (2 & 3), SFML (2 & 3), raylib
  • GUI: GTK (2, 3 & 4), Qt6, VTE
  • Audio: OpenAL, SDL2_mixer, PipeWire, rtaudio
  • Physics: Box2D, ReactPhysics3D
  • Other: Boost, libconfig++, FastCGI, Gio/GLib, X11

For versioned libraries, the newest available version is preferred (e.g. GTK 4 over GTK 3, SFML 3 over SFML 2).

When a build fails due to a missing header, Slay will suggest which package to install (using pkgfile on Arch Linux or apt-file on Debian/Ubuntu).

Examples

Over 40 examples are included in the examples/ directory:

Category Examples
Basics hello, args, lambda, defer, invoke, visit, async, designated, entities, validorder, findfiles, platforms, config
Graphics sfml, sfml_audio, bisqwit, sdl2, sdl2_opengl, sdl3, gles3_sdl3, gl4_spirv, gles2_glfw, gles3_glfw, glm, raylib, raylib5, vulkan, vulkan_glfw, x11, x11_opengl, smallpt
GUI gtk4, gtk4ui, dunnetgtk, qt6
Audio openal, synth, mixer, pipewire, rtaudio
Physics box2d, reactphysics
Other boost, boost_thread, notify, fastcgi, tinyhello, win64crate

Build all examples:

make examples

Packaging

Install to a package directory:

DESTDIR="$pkgdir" PREFIX=/usr slay install

Or package into a local pkg/ directory:

slay pkg

Generate standalone build files for users without slay:

slay export    # generates Makefile + build.sh + clean.sh

Cross-Compilation

Build for 64-bit Windows (requires x86_64-w64-mingw32-g++ or Docker):

slay win64
slay small win64
slay tiny win64

Test Windows executables with Wine:

slay run    # after slay win64, uses wine automatically

Source Code Formatting

slay fmt    # formats source code using clang-format (Webkit style)

The formatting style is fixed and not configurable, on purpose.

Requirements

  • g++ with C++23 support (or later)
  • pkg-config
  • make (for the project Makefile, not for building C++ projects)

Optional

  • clang++ — build with slay clang
  • lldb or gdb — for debugging
  • pkgfile (Arch Linux) or apt-file (Debian/Ubuntu) — for missing-package suggestions
  • x86_64-w64-mingw32-g++ or docker — for Windows cross-compilation
  • wine — for testing Windows executables
  • valgrind — for profiling (slay valgrind)
  • clang-format — for slay fmt
  • ninja — for slay ninja / slay cmake ninja

Arch Linux (all examples)

sudo pacman -S --needed base-devel boost box2d fcgi freeglut glew glfw glibmm glm glu \
  gtk4 libconfig libpipewire libx11 openal qt6-base raylib \
  rtaudio sdl2-compat sdl2_mixer sdl3 sfml vte4 vulkan-headers vulkan-icd-loader

Debian / Ubuntu (all examples)

sudo apt-get install -y build-essential pkg-config \
  libboost-all-dev libconfig++-dev libfcgi-dev libglew-dev libglfw3-dev \
  libglibmm-2.4-dev libglm-dev libglu1-mesa-dev libgtk-4-dev libopenal-dev \
  libpipewire-0.3-dev libsdl2-dev libsdl2-mixer-dev libsfml-dev \
  libvte-2.91-gtk4-dev libvulkan-dev libx11-dev freeglut3-dev qt6-base-dev

Note: raylib and reactphysics3d are not available in Ubuntu repositories and reactphysics3d is no longer in the official Arch Linux repositories. Ubuntu 24.04 ships SFML 2 and rtaudio 5, while the included examples use SFML 3 and rtaudio 6 APIs — those examples will be skipped on Ubuntu. Examples that depend on unavailable libraries are automatically skipped in CI.

Platform Notes

macOS

Install a recent GCC and dependencies with Homebrew:

brew install gcc pkg-config

FreeBSD / NetBSD

Use gmake instead of make. Install dependencies:

# FreeBSD
pkg install pkgconf gmake

# NetBSD
pkgin install pkgconf gmake

OpenBSD

Install g++ 11+ and build with slay CXX=eg++.

Windows

Windows is supported via two development environments:

MSYS2 (recommended): Install MSYS2, then use pacman to install libraries:

pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-pkg-config
pacman -S mingw-w64-x86_64-SDL2   # example: install SDL2

Slay auto-detects the MSYS2 environment via the MSYSTEM variable and uses pacman for package resolution, similar to Arch Linux.

vcpkg: Install vcpkg and set VCPKG_ROOT or add vcpkg to your PATH:

vcpkg install sdl2   # example: install SDL2

Slay uses vcpkg's pkg-config files and installed tree for library resolution. The default triplet is x64-windows (override with VCPKG_DEFAULT_TRIPLET).

In both cases, a GCC or Clang compiler must be available on PATH.

Features and Limitations

  • No configuration files needed — follows the directory structure conventions above.
  • Auto-detection of compiler flags, includes and libraries via pkg-config and platform-specific package managers.
  • Incremental compilation — only recompiles changed source files.
  • Profile-guided optimizationslay rec collects profiling data, subsequent builds use it.
  • Built-in support for testing, debugging, cross-compilation, and code generation.
  • Meant for building executables, not libraries.
  • Generated CMakeLists.txt is specific to the system it was generated on.

General Info

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ProgName = "slay"
	ProgURL  = "https://github.com/xyproto/slay"
)
View Source
var SourceExts = []string{".cpp", ".cc", ".cxx", ".c"}

SourceExts are the recognized C/C++ source file extensions.

Functions

func CompileSources

func CompileSources(srcs []string, output string, flags BuildFlags) error

func DoBuild

func DoBuild(opts BuildOptions) error

func DoCMakeBuild

func DoCMakeBuild(opts BuildOptions) error

func DoExport

func DoExport() error

func DoGenerate

func DoGenerate(opts BuildOptions) error

func DoGenerateMakefile

func DoGenerateMakefile() error

func DoInstall

func DoInstall() error

func DoMake

func DoMake() error

func DoMakeClean added in v1.3.1

func DoMakeClean()

func DoMakeInstall added in v1.3.1

func DoMakeInstall() error

func DoNinja

func DoNinja() error

func DoNinjaClean

func DoNinjaClean()

func DoNinjaInstall

func DoNinjaInstall() error

func DoPkg

func DoPkg() error

func DoPro

func DoPro(opts BuildOptions) error

func DoScript

func DoScript() error

func DotSlash

func DotSlash(name string) string

func ExecutableName

func ExecutableName() string

func GetMainSourceFile

func GetMainSourceFile(testSrcs []string) string

GetMainSourceFile finds the main C/C++ source file in the current directory.

func GetTestSources

func GetTestSources() []string

Types

type BuildFlags

type BuildFlags struct {
	Compiler       string
	Std            string
	ContainerImage string // if set, compile via "docker run" or "podman run" with this image
	CFlags         []string
	LDFlags        []string
	Defines        []string
	IncPaths       []string
}

BuildFlags holds the assembled compiler and linker flags.

func AssembleFlags

func AssembleFlags(proj Project, opts BuildOptions) BuildFlags

type BuildOptions

type BuildOptions struct {
	InstallPrefix   string // If set, override dir defines with install paths
	Debug           bool
	Opt             bool
	Strict          bool
	Sloppy          bool
	Small           bool
	Tiny            bool
	Clang           bool
	Zap             bool
	Win64           bool
	NoSanitizers    bool
	ProfileGenerate bool
	ProfileUse      bool
}

BuildOptions holds the configuration for a build.

type BuildResult

type BuildResult struct {
	OutputExecutable string   // name of the produced executable (relative to sourceDir)
	Output           []byte   // combined compiler output (stdout+stderr)
	CommandsRun      []string // shell-style command strings that were executed
}

BuildResult contains the results of a build operation.

func Build

func Build(sourceDir string, opts BuildOptions) (BuildResult, error)

Build compiles the C/C++ project in the given directory. It detects sources, dependencies, and required flags automatically. The sourceDir is the directory containing the source files.

type Config

type Config struct {
	SourceDir string // if set, operate in this directory instead of the current one
	BuildOptions
}

Config holds the full configuration for an slay operation.

func ClangConfig

func ClangConfig() *Config

ClangConfig returns a Config that uses clang/clang++.

func DebugConfig

func DebugConfig() *Config

DebugConfig returns a Config for debug builds with sanitizers.

func DebugNoSanConfig

func DebugNoSanConfig() *Config

DebugNoSanConfig returns a Config for debug builds without sanitizers.

func NewConfig

func NewConfig() *Config

NewConfig returns a Config with default settings (standard build).

func OptConfig

func OptConfig() *Config

OptConfig returns a Config for optimized builds (-Ofast/-O3, -flto).

func SloppyConfig

func SloppyConfig() *Config

SloppyConfig returns a Config with permissive compilation flags.

func SmallConfig

func SmallConfig() *Config

SmallConfig returns a Config for size-optimized builds (-Os).

func SmallWin64Config

func SmallWin64Config() *Config

SmallWin64Config returns a Config for size-optimized Windows cross-compilation.

func StrictConfig

func StrictConfig() *Config

StrictConfig returns a Config with strict warning flags.

func TinyConfig

func TinyConfig() *Config

TinyConfig returns a Config for minimal-size builds (-Os + sstrip/upx).

func TinyWin64Config

func TinyWin64Config() *Config

TinyWin64Config returns a Config for minimal-size Windows cross-compilation.

func Win64Config

func Win64Config() *Config

Win64Config returns a Config for cross-compiling to 64-bit Windows.

func ZapConfig

func ZapConfig() *Config

ZapConfig returns a Config that uses zapcc++.

func (*Config) Build

func (c *Config) Build() error

Build compiles the project using the configured options.

func (*Config) CMakeBuild

func (c *Config) CMakeBuild() error

CMakeBuild builds using cmake, preferring ninja over make. Generates CMakeLists.txt first if it does not exist.

func (*Config) CMakeMakeClean

func (c *Config) CMakeMakeClean()

CMakeMakeClean cleans a make or cmake+make build.

func (*Config) CMakeMakeInstall

func (c *Config) CMakeMakeInstall() error

CMakeMakeInstall installs from a make or cmake+make build.

func (*Config) Clean

func (c *Config) Clean()

Clean removes all build artifacts: runs make clean, ninja clean, removes the build/ directory, and cleans object files and executables.

func (*Config) Export

func (c *Config) Export() error

Export generates a standalone Makefile, build.sh, and clean.sh.

func (*Config) FastClean

func (c *Config) FastClean()

FastClean removes only the executable and object files.

func (*Config) Fmt

func (c *Config) Fmt() error

Fmt formats source code using clang-format.

func (*Config) Generate

func (c *Config) Generate() error

Generate generates a CMakeLists.txt file.

func (*Config) GenerateMakefile

func (c *Config) GenerateMakefile() error

GenerateMakefile generates a standalone Makefile.

func (*Config) Install

func (c *Config) Install() error

Install builds and installs the project (using PREFIX and DESTDIR environment variables).

func (*Config) LaunchDebugger

func (c *Config) LaunchDebugger() error

LaunchDebugger builds a debug version and launches the appropriate debugger. Uses lldb first when Clang is set, otherwise prefers cgdb/gdb.

func (*Config) Make

func (c *Config) Make() error

Make builds using make. If a Makefile exists, runs make directly. Otherwise falls back to cmake+make if CMakeLists.txt exists.

func (*Config) Ninja

func (c *Config) Ninja() error

Ninja builds using ninja. If build/build.ninja exists, runs ninja directly. Otherwise falls back to cmake+ninja if CMakeLists.txt exists.

func (*Config) NinjaClean

func (c *Config) NinjaClean()

NinjaClean removes the ninja build directory.

func (*Config) NinjaInstall

func (c *Config) NinjaInstall() error

NinjaInstall installs from a ninja build.

func (*Config) Pkg

func (c *Config) Pkg() error

Pkg packages the project into a pkg/ directory.

func (*Config) Pro

func (c *Config) Pro() error

Pro generates a QtCreator .pro project file.

func (*Config) Rebuild

func (c *Config) Rebuild() error

Rebuild cleans and then builds the project.

func (*Config) Rec

func (c *Config) Rec(args ...string) error

Rec performs profile-guided optimization: clean, build with profiling, run, rebuild with profile data.

func (*Config) Run

func (c *Config) Run(args ...string) error

Run builds the project and runs the resulting executable.

func (*Config) RunBuilt

func (c *Config) RunBuilt(args ...string) error

RunBuilt runs an already-built executable without rebuilding.

func (*Config) Script

func (c *Config) Script() error

Script generates build.sh and clean.sh scripts.

func (*Config) Test

func (c *Config) Test() error

Test builds and runs all test files.

func (*Config) TestBuild

func (c *Config) TestBuild() error

TestBuild builds the main executable and all test files without running them.

func (*Config) TinyBuild

func (c *Config) TinyBuild() error

TinyBuild builds with the configured options and applies sstrip/upx post-processing.

func (*Config) Valgrind

func (c *Config) Valgrind() error

Valgrind builds the project and profiles it with valgrind/callgrind.

type Project

type Project struct {
	MainSource    string
	DepSources    []string
	TestSources   []string
	Includes      []string // external includes from source files
	BoostLibs     []string
	IsC           bool // true if main source is a .c file
	HasOpenMP     bool
	HasBoost      bool
	HasQt6        bool
	HasMathLib    bool
	HasFS         bool
	HasThreads    bool
	HasWin64      bool // detected from #include <windows.h>
	HasGLFWVulkan bool // detected from #define GLFW_INCLUDE_VULKAN
	HasDlopen     bool // detected from #include <dlfcn.h>
}

Project holds all detected project information.

func DetectProject

func DetectProject() Project

Directories

Path Synopsis
cmd
slay command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL