Skip to content

xyproto/slay

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

161 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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 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:

Builds 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

About

Configuration-free utility for building, testing and packaging executables written in C and C++. Can auto-detect compilation flags based on includes, via the package system and pkg-config.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors