Thu 30 April 2026

🌷 Sane C++ April 26

SC

Welcome to the April 2026 update!
This month makes SC::Build much more practical as the default native workflow, a real cross-compilation tool, and an easier entry point for external projects.

Build Native Backend

April has been almost entirely about SC::Build. The biggest milestone is that the native generator is now the default on all supported host platforms, so the direct compile / run workflow is no longer some experimental side path.

This is where the project is becoming much more interesting to me, because the native backend is also where cross targets, foreign-binary execution and the nicer bootstrap story are all landing. Generated backends are still useful, but at this point the standalone builder is clearly becoming the main workflow.

There is also now an experimental Fil-C target in the mix. It is still very early, but I really like seeing SC::Build start to expose weirder compiler / toolchain combinations inside the same workflow. I also posted a short note about it here:

Detailed list of commits:

Cross-Compilation

The next big theme has been making cross-compilation feel like a real supported workflow instead of a bag of flags. SC::Build now has friendly Linux and Windows target profiles, packaged sysroots, llvm-mingw support, and raw --triple / --sysroot escape hatches for when one wants to go off the beaten path.

This is not the flashiest work in the world, but it changes a lot in practice. Once target profiles, sysroots and packaged toolchains are wired together properly, building for another platform starts feeling boring in the good way, instead of like a custom one-off setup.

Detailed list of commits:

Runners and Cross-Runs

Producing foreign binaries is only half the story. This month also makes them much easier to execute, with much better Wine and QEMU integration across different host and target combinations.

There has been a lot of fiddly work here around Linux ARM64, portable MSVC packaging, auto-resolved wrappers and managed runner registration. The nice result on the user side is that build run is increasingly able to do something sensible automatically even when the executable does not match the host platform, which is exactly what I wanted from this tool.

Detailed list of commits:

External Builds

Another important change is that SC::Build is becoming easier to use outside of the main repository. The new external launchers and bootstrap flow make it much simpler to point a standalone project at a Sane C++ checkout, or even use a shared cached checkout, without having to copy the repository workflow by hand.

This is especially useful for small external experiments and tests, because the build-definition file can stay tiny while still pulling in the Sane C++ libraries and the right public headers automatically. The additions around shared helpers, defaults and SC_BUILD self-detection also make it easier for a single SC-build.cpp file to act both as build script and as project source when needed, which is a pretty nice trick for tiny examples.

For example, an external project can just curl the launcher, write a tiny SC-build.cpp, and compile immediately:

#include "SaneCppBuild.h"

SC::Result SC::Build::configure(Definition& definition, const Parameters& parameters)
{
    Project project = {"MyProject"};
    SC_TRY(Build::addSaneCppLibraries(project, parameters));
    SC_TRY(project.addFile("main.cpp"));
    return definition.addProject(move(project));
}
curl -L -o SC-build.sh https://raw.githubusercontent.com/Pagghiu/SaneCppLibraries/main/SC-build.sh
chmod +x SC-build.sh
./SC-build.sh run

I like this a lot because it starts making SC::Build feel usable as a general standalone tool, not only as the thing used to build this repository itself.

Detailed list of commits:

Public Headers

The external-project story is also much better now because there are explicit public headers whose names match the single-file library variants. This means external users can include headers such as SaneCppStrings.h or SaneCppHttp.h in a much more obvious way, while keeping the door open to switch between single-file and multi-file integration styles with much less friction.

I think this is a very nice change for usability. If the public header names match the single-file library names, users do not need to care as much about how things are packaged internally, and moving between the two styles becomes much less annoying.

Detailed list of commits:

Build Ergonomics and CI

There has also been a steady stream of work on polishing the day-to-day experience around the builder and its CI coverage. This includes better output handling, more flexible CLI parsing, self-tests for the build system itself, and a lot of cache work to keep workflows lighter and less repetitive.

These changes are less visible than target-profile support or cross-runners, but they are the sort of things that stop a build tool from feeling fragile. Also, a lot of this month has been about making the CI less wasteful, because waiting on giant caches all the time is just boring.

Detailed list of commits:

Others

Outside SC::Build, the month also includes a few useful portability and quality-of-life changes. Async loop timeout tests got some stabilization work, runtime path resolution became more portable across build targets, MinGW compilation support improved, and Strings gained case-insensitive helpers.

This section is smaller than usual, but that is mostly because April has been totally dominated by build-system work.

Detailed list of commits:

See you next month!