SC::Build is a Tool and public API for describing builds in C++ and then either generating project files or building directly through a standalone native backend.
SC-build.cpp using SC::Build::Definition, Workspace, Project, and ConfigurationSC::Build::Generator::Native on macOS, Linux, and Windows hostscompile_commands.json on the native backend and from the Make / XCode generated flowsSC-package from Tools to download repository dependenciesaddExportLibraries and addExportAllLibraries🟨 MVP
SC::Build is used by this repository to generate projects and/or build the test suites, tools, examples, and the SC shared library. The standalone native backend is now the default day-to-day workflow on macOS, Linux, and Windows, while the generated-project backends remain available for IDE and project-file flows.
Build descriptions are regular C++ files, conventionally named SC-build.cpp, that are compiled on the fly through the repository bootstraps SC.sh / SC.bat or the external-project launchers SC-build.sh / SC-build.bat / SC-build.ps1.
For the external bootstrap workflow, including vendored, shared-checkout, and standalone-cache usage, see External SC::Build Bootstrap.
The same public API serves two workflows:
_Build/_ProjectsThe repository tool surface is the SC-build tool described in Tools. Its normal command-line shape is:
Generated-project workflows also use:
Named options accepted by compile, run, and coverage are:
-c, --config <NAME>-g, --generator <NAME>-a, --arch <NAME>--target <PROFILE> (compile and run only)--toolchain <NAME>--triple <VALUE>--sysroot <PATH>--runner <MODE> (run only)--runner-path <PATH> (run only)-o, --output <MODE> (compile and run only)-q, --quiet (compile and run only)--normal (compile and run only)-v, --verbose (compile and run only)Generator values accepted by the tool are:
defaultnativemakexcodevs2022vs2019Architecture values accepted by the tool are:
arm64intel64intel32wasmanyTarget profiles accepted by the tool today are:
hostnativelinux-glibc-x86_64linux-glibc-arm64linux-musl-x86_64linux-musl-arm64windows-gnu-x86_64windows-msvc-x86_64windows-msvc-arm64windows-gnu-arm64Runner values accepted by build run today are:
autononewineqemucustomToolchain values accepted by compile and run today are:
defaulthost-defaultclangfilcgccmsvcclang-clllvm-mingwCurrent CLI behavior:
compile builds the whole default workspacerun requires a single executable target and forwards arguments placed after --Debug is usednative on Windows, macOS, and Linuxconfigure is primarily for generated backends; normal native compile / run flows build directly into _Build/_Outputs and _Build/_Intermediatescompile / run accept quiet, normal, or verbose output control through --output or the --quiet / --normal / --verbose shortcuts--target selects a friendly host or cross target profile without requiring the caller to spell the toolchain triple manually--toolchain selects the compiler family orthogonally to --target--abi is reserved for a future public ABI selector; use --target for glibc, musl, GNU, or MSVC selection today--triple and --sysroot are raw escape hatches for advanced toolchain overrides--target, so they win over the friendly profile defaultsbuild run can use --runner / --runner-path to control how foreign executables are launched--runner auto prefers direct execution for runnable native Linux outputs before falling back to Wine or QEMU--generator, --arch, --runner, or --triple values now fail early with concrete CLI errorstarget as [configuration] [generator] [architecture] [output-mode]This is the repository Tools/SC-build.cpp file used to configure the default workspace:
The public API in Tools/SC-build/Build.h currently exposes:
Definition, Workspace, Project, and Configuration for the build graphLibraries::{SingleFile, Multiple} plus addSaneCppLibraries(...) for adding Sane C++ Libraries to a targetMachine and TargetEnvironment for explicit host / target modelingTargetType::{ConsoleExecutable, GUIApplication, SharedLibrary, StaticLibrary}Generator::{Native, XCode, VisualStudio2022, VisualStudio2019, Make}Toolchain::{HostDefault, Clang, FilC, GCC, MSVC, ClangCL, LLVMMingw, CustomDriver}RunnerSpec::{Auto, None, Wine, QEMU, Custom}SupportMatrixEntry, SupportStatus, SupportTier, and getNativeBackendSupportMatrix() for the native-backend cross-compilation support matrixExecutionOptions for native-backend parallelism / verbosity knobsOutputMode::{Quiet, Normal, Verbose} and ExecutionOptions::outputMode for native-backend presentation controlDirectories::projectDirectory for the root of the project being configured, distinct from the SaneCppLibraries checkoutProject::addSpecificFileFlags for per-file flag groupsProject::addExportLibraries, addExportAllLibraries, and addExportDirectories for plugin host exportsProject::saneCpp and Configuration::saneCpp for Sane C++ Libraries specific policy flags such as strict no-standard-library modeExternal SC-build.cpp files can add Sane C++ Libraries to a project with:
This defaults to Libraries::SingleFile, which adds SC.cpp.
To compile the individual library sources instead, use:
Call the helper after setting the project root directory, typically with project.setRootDirectory(parameters.directories.projectDirectory.view()).
SC-build is a general-purpose build system, so generic C++ standard-library policy lives in generic compile/link flags. Normal mode is the default: standard C/C++ headers are available and the C++ standard-library runtime may be linked. Sane C++ Libraries specific options are grouped under saneCpp and are enabled automatically by addSaneCppLibraries().
To request the stricter historical no-stdlib pressure mode for an entire Sane C++ target:
For a single configuration:
The generic includeStdCpp flag controls whether the backend passes best-effort no-standard-C++-include flags such as -nostdinc++. When saneCpp.enabled is true, SC-build also emits SC_INCLUDE_STD_CPP from that generic compile flag.
Targets that intentionally use STL runtime features can opt into C++ standard-library linkage:
If a Sane C++ target avoids linking the C++ runtime, it must either provide the runtime ABI shims itself or obtain them from another object/library:
SC-build rejects project.link.linkStdCpp = true together with project.saneCpp.provideCppRuntimeShims = true because both sides would be trying to provide the same C++ runtime ABI symbols.
The repository bootstrap keeps broad compiler compatibility for headers by default while still avoiding C++ runtime linkage. Set SC_BOOTSTRAP_INCLUDE_STD_CPP=0 only when you intentionally want to test or benchmark strict-mode bootstrap compilation. Set SC_BOOTSTRAP_LINK_STD_CPP=1 if you explicitly want the bootstrap tool to link the C++ standard-library runtime.
| Backend | Platforms | Target kinds | compile_commands.json | Notes |
|---|---|---|---|---|
Native | macOS, Linux, Windows hosts | Console executable, GUI application, shared library, static library | Yes | Direct compile / run / coverage flow; no project files are generated |
XCode | Apple | Console executable, GUI application, shared library, static library | Yes | GUI apps also emit storyboard / assets; Intel32 and Wasm architectures are unsupported |
VisualStudio2022 / VisualStudio2019 | Windows | Console executable, GUI application, shared library, static library | No | Explicit generated-project workflow for Visual Studio |
Make | Apple, Linux | Console executable, GUI application, shared library, static library | Yes on clang-style flows | Explicit generated-project workflow for Make; GCC builds still compile, but Makefile-side compile database generation is unavailable there |
The native backend exposes its current cross-compilation support claims through Build::getNativeBackendSupportMatrix(). Documentation and CI should treat that API as the source of truth for host / target rows, build support, run support, support tier, runner family, and validation notes.
| Host | Target | Architecture | Build | Run | Runner | Tier |
|---|---|---|---|---|---|---|
| macOS | windows-gnu | x86_64 | supported | supported | wine | tier1 |
| macOS | windows-gnu | arm64 | supported | not-yet | wine | tier1 |
| macOS | windows-msvc | x86_64 | supported | smoke-supported | wine | tier2 |
| macOS | windows-msvc | arm64 | supported | not-yet | wine | tier2 |
| macOS | linux-glibc | x86_64 | supported | not-yet | qemu | tier1 |
| macOS | linux-glibc | arm64 | supported | not-yet | qemu | tier1 |
| macOS | linux-musl | x86_64 | supported | not-yet | qemu | tier1 |
| macOS | linux-musl | arm64 | supported | not-yet | qemu | tier1 |
| Windows | linux-glibc | arm64 | supported | not-yet | qemu | tier2 |
| Windows | linux-musl | x86_64 | supported | not-yet | qemu | tier2 |
| Linux | windows-gnu | x86_64 | supported | supported | wine | tier1 |
| Linux | windows-gnu | arm64 | supported | smoke-supported | wine | tier1 |
| Linux | windows-msvc | x86_64 | supported | smoke-supported | wine | tier2 |
| Linux | windows-msvc | arm64 | supported | smoke-supported | wine | tier2 |
The standalone backend is selected through SC::Build::Generator::Native.
Current implemented scope:
HostDefault, Clang, FilC, GCC, MSVC, ClangCL, LLVMMingw, and CustomDriverFilC is now exposed by the API and CLI through --toolchain filc, but it is Linux-only, compiler-first, and toolchain-only for now; no public linux-filc-* target profile existsExecutionOptions::maxParallelJobsquiet hides progress lines and successful child output, normal shows progress plus grouped failures and summaries, and verbose also shows rebuild traces, skip lines, and successful compile output_Build/_Outputs, _Build/_Intermediates, and _Build/_BuildCacheCurrent cross-compilation scope:
windows-gnu-x86_64 and windows-gnu-arm64 through packaged llvm-mingwSC-package install filc plus build ... --toolchain filc; this is currently limited to native Linux x86_64 output and remains toolchain-only outside the public target-profile matrixglibc and musl target profiles now exist as first-class native-backend profiles; they shape canonical target triples and sysroot flags, and macOS hosts now auto-select both a packaged LLVM toolchain and packaged Linux sysroots for them when the caller has not provided explicit compiler pathsSCTest compile validation for linux-glibc-x86_64, linux-glibc-arm64, linux-musl-x86_64, and linux-musl-arm64build run can now wrap foreign Linux targets through qemu-user; the native runner can reuse a managed SC-package install qemu registration or fall back to host qemu-* executables from PATH, and it passes -L <sysroot> so dynamically linked Linux targets can find their loader and librariesnot-yet in the support matrix; real host-QEMU validation remains opportunistic until CI can acquire qemu-x86_64 and qemu-aarch64 deterministicallylinux-glibc-arm64 and linux-musl-x86_64 target profiles; Windows-host Linux runs remain pending./SC.sh package install msvc and compile windows-msvc-x86_64 and windows-msvc-arm64 through the native backendwindows-msvc-x86_64 and windows-msvc-arm64; the package tool auto-prefers a generated box64 + wine64 wrapper when those host tools are installed, can fall back to an auto-installed packaged Linux Wine runner that resolves a maintained generic-arm box64 build when system box64 is absent, and native build run can now auto-install a separate ARM64 Wine runtime for windows-*-arm64 execution while still accepting plain wine64 / wine or an explicit --wine / SC_MSVC_WINE overrideSC-package install msvc also accepts explicit --import-directory <path> and --wine <path> overrides so imported layouts and custom Wine wrappers no longer have to be driven only through environment variablessc-msvc-package.json instead of requiring SC_MSVC_WINE or host Wine discovery againsc-msvc-package.json metadata and wrapper scripts in place, and SDK version detection now falls back from Windows Kits/10/bin to Include or Lib when the SDK tools directory is absentmacOS vs Linux) so shared workspaces do not reuse the wrong recorded Wine runner path across hostswindows-msvc-x86_64 has a clean native-backend SCTest compile validation plus a targeted BaseTest/new-delete run through the maintained packaged Box64 runner, and windows-msvc-arm64 now also has a clean native-backend SCTest compile plus a targeted BaseTest/new-delete run through an auto-installed native ARM64 Wine runnerbuild run now keeps Windows console targets on plain packaged wine instead of auto-switching to wineconsole, because the current Box64 Wine console path is less reliable than plain wine on this hostbuild run can auto-route windows-gnu-x86_64 executables through Wine on macOS and Linux, and Linux arm64 now also smoke-runs windows-gnu-arm64 through the packaged native ARM64 Wine runnerbuild run path now auto-prefers generated box64 + wine64 wrappers when the host provides those commands, and console targets still switch to a sibling wineconsole --backend=curses wrapper when it is available on Linux x64 hostswindows-msvc-x86_64, while Linux arm64 now has targeted SCTest BaseTest/new-delete smokes for both windows-msvc-x86_64 and windows-msvc-arm64build run now routes Wine launches through cmd /c with Windows-style paths, which fixes real macOS Wine startup for windows-gnu-x86_64windows-gnu-arm64 and windows-msvc-arm64 are no longer blocked by a hardcoded CLI rule; Linux arm64 now has a real ARM64-capable Wine runtime for targeted smokes, while the packaged macOS Wine runner still does not ship an ARM64 Windows loaderThe friendly --target profiles select the target platform, architecture, environment and default toolchain family. Use --toolchain, --triple or --sysroot only when you need to override that resolved profile. build run --runner auto first chooses direct execution for runnable native Linux outputs, then falls back to Wine for Windows targets or QEMU for foreign Linux targets when that row is supported by the host.
Prepare package-managed inputs before relying on a cross row:
Compile Linux targets from macOS with the packaged LLVM and sysroot receipts:
Register QEMU when a host has a known qemu-user layout and you want foreign Linux build run smoke tests:
Compile and smoke-run Windows GNU targets through the shared Wine runner model:
Compile portable MSVC targets after acquiring the packaged toolchain:
On Windows hosts, the Linux rows are compile-only today:
Future preset hooks should compose the same public vocabulary instead of introducing parallel names: target=<profile>, toolchain=<name>, runner=<auto|none|wine|qemu|custom>, runner-path=<path>, triple=<value> and sysroot=<path>. A preset for a cross row should therefore expand to the same options shown above, plus package checks such as SC-package verify or SC-package lock when it depends on managed inputs.
Typical native commands:
Important current limits:
qemu-user layout or host qemu-* executables; real host-QEMU smoke validation remains opportunistic on macOS until QEMU-user acquisition is deterministic in CI, so macOS Linux run support stays not-yet--toolchain filc, no public linux-filc-* target profile exists, Linux x86_64 is the only intended output slice for the first milestone, and Linux arm64 hosts may still require imported local installs plus host-specific translation/linker helpers during validationbuild run installs/rebuilds zlib-filc on demand and prepends that package's lib directory to LD_LIBRARY_PATH so zlib-backed tests load a Fil-C-built libz.so.1run is valid only for executable targets and only when a single project is selectedbuild configure command remains available for generated-project workflows; native builds do not need generated project files firstProject::addSpecificFileFlags is implemented and used by this repository.
The current backend behavior is:
| Backend | Per-file behavior |
|---|---|
Native | Full compile-flag merge for the selected files |
Make | Full compile-flag merge, emitted as grouped per-file variables in the generated Makefile |
XCode | Per-file include paths, defines, and non-MSVC warning disables are emitted; other per-file compile knobs are not yet emitted, and conflicting higher-level flags cannot be removed |
VisualStudio2019 / VisualStudio2022 | Per-file include paths, defines, and MSVC warning disables are emitted; other per-file compile knobs are not yet emitted |
The repository example lives in Tools/SC-build.cpp, where the SCTest target applies a dedicated define, include path, and warning disables to a selected subset of files.
SC_BUILD DefineWhen SC-build.cpp is compiled as the build-definition tool, SC::Build defines SC_BUILD=1 for that compilation.
This allows one SC-build.cpp file to provide SC::Build::configure(...) in the SC_BUILD branch and a normal main() in the #else branch if the same file is also added to the built target.
For host executables using the Plugin library:
Project::addExportLibraries adds the needed SC_EXPORT_LIBRARY_<LIBRARY>=1 defines to the host executableProject::addExportAllLibraries does the same for every Sane C++ library-rdynamicLinkFlags::preserveExportedSymbols currently performs fine-grained exported-symbol preservation only on the standalone native backend and on generated Makefiles. The XCode backend currently falls back to disabling dead-code stripping when preservation is requested.
Repository-generated paths are currently:
_Build/_Projects/XCode/SCWorkspace/..._Build/_Projects/VisualStudio2022/SCWorkspace/..._Build/_Projects/VisualStudio2019/SCWorkspace/..._Build/_Projects/Make/SCWorkspace/apple/..._Build/_Projects/Make/SCWorkspace/linux/..._Build/_Outputs/<expanded-configuration>/..._Build/_Intermediates/<project>/<expanded-configuration>/..._Build/_Intermediates/<workspace>/compile_commands.json for native workspace databases_Build/_BuildCache/... for native-backend stateSC-build itself through one of the repository build tasks or through build compileSC-build executable under your debugger with the same arguments passed by the bootstrapUse build configure when you explicitly want generated projects for IDEs or Make:
Typical examples:
_Build/_Projects/XCode/SCWorkspace/SCWorkspace.xcworkspace_Build/_Projects/VisualStudio2022/SCWorkspace/SCWorkspace.sln_Build/_Projects/Make/SCWorkspace/apple or _Build/_Projects/Make/SCWorkspace/linuxWindows runtime targets are long-path-aware by default. Override this with project.windows.longPathAware or config.windows.longPathAware when generating Windows targets. The option is valid for console executables, GUI applications, and shared libraries; static libraries reject it during validation.
With any debugger or IDE other than VSCode, debug _Build/_Tools/<Platform>/SC-build (or _Build/_Tools/Windows/SC-build.exe) and pass arguments similar to:
This is the list of videos that have been recorded showing some of the internal thoughts that have been going into this library:
Some relevant blog posts are: