Sane C++ tools are small C++ programs compiled on demand by the repository bootstrap. They automate repository work without introducing another scripting runtime, and they exercise the same libraries that application code uses.
A tool can use Process, FileSystem, Hashing, Http, and the other libraries directly. It can be debugged with a normal C++ debugger, share result-handling conventions with the repository, and run on macOS, Linux, and Windows.
The tradeoff is explicit: a working host C++ compiler is required to bootstrap the first tool. After that, unchanged tool support code is reused from _Build, so ordinary invocations only rebuild what changed.
The first argument to SC.sh or SC.bat selects a tool. The next argument selects an action owned by that tool:
For example:
The words after the tool name matter. build compile stops after producing the target; build run brings the target up to date and then launches it. Arguments after -- are forwarded to the launched program.
External projects use the dedicated SC-build.sh, SC-build.ps1, or SC-build.bat launchers described in SC::Build (External use).
Pass the path of a tool source file instead of a built-in name:
A tool implements Tools::Tool::runTool and receives the selected action, remaining arguments, repository paths, and a console:
Use this form for repository-local automation that benefits from Sane C++ APIs. A standalone application with its own targets belongs in SC::Build instead.
SC-build reads the repository's C++ build definition and performs compile, run, coverage, documentation, or generated-project configure actions. Learn its model and first workflow in SC::Build.
Keep two rules in mind:
--, so they are not parsed as build options.SC::Package acquires development tools, compilers, sysroots, and runners used by repository workflows. It is not an application dependency manager: packages live under _Build and support building, formatting, documentation, and cross-target validation.
Every package has three useful layers:
After installation or import, validation produces a receipt and a set of named exports. This allows SC::Build to ask for a capability such as an LLVM compiler or QEMU runner without reconstructing an installation path from directory naming conventions.
Start with read-only actions:
status reports whether a receipt is present and structurally valid without failing merely because a package is missing. verify performs the stricter validation used when a workflow depends on that package:
When validation fails, doctor explains the observed state and suggests a next action:
Install a package managed by the built-in catalog:
Some large or host-specific tools can be registered from an existing directory instead of downloaded:
Fil-C 0.686 is available on native Linux Intel64 (x86_64) and ARM64 (aarch64) hosts. package install filc selects the host-matching archive; an imported compiler must report the matching Linux target triple. The resulting toolchain capability is toolchain.filc.x86_64 or toolchain.filc.aarch64, respectively.
Install native patchelf first (for example, sudo apt-get install patchelf on Ubuntu). The rootless release setup uses it to configure its bundled runtime. Download the host-matching release with:
To register an existing ARM64 installation, use:
For an Intel64 host, use the corresponding filc-0.686-linux-x86_64 import directory.
The separate experimental glibc profile requires the host-matching upstream /opt/fil distribution to be installed beforehand. SC-Build does not perform privileged installation or replace system libraries:
This profile uses separate filc-glibc output/intermediate directories, /opt/fil/lib for runtime dependencies, and the bundled libc++abi for TLS destructor registration. The compiler-selected Fil-C loader already searches /opt/fil/lib; the runner does not inject that path into LD_LIBRARY_PATH, so native subprocesses retain their normal library lookup. User-provided loader environment variables are still inherited. It never prepares or loads the rootless package-local dependencies. Fiber contexts require explicit runtime-owned stacks and a thread-pinned scheduler opt-in; caller-stack/guard-page modes and multi-threaded fiber scheduling remain unsupported. Always-on CI continues to use the rootless profile. The separate Fil-C Fibers workflow validates the glibc profile in Release on native ARM Linux weekly, on manual dispatch, and on relevant pushes to the experimental filc branch, without duplicating the always-on matrix. It caches a checksum-pinned upstream archive and installs only its /opt/fil payload on disposable hosted runners. For a preinstalled local distribution, run ./Support/Scripts/RunFilCFiberTests.sh Debug (or Release). This runner requires actual runtime-owned stack support; unsupported-path test results cannot pass it.
Fil-C 0.686 also supports the separate experimental C++20 Await target, without linking the C++ standard-library runtime. Build before running it:
Use --toolchain filc for the rootless profile. The glibc workflow checks full Await in Release; always-on rootless CI checks the small no-standard-header coroutine shim to avoid duplicating a full library build. Upstream describes coroutine support as initial and notes possible additional stack-overflow panics; see the 0.686 release notes. This does not change the fiber stack-ownership or migration restrictions above.
Rootless --toolchain filc runs also prepare package-local zlib-filc, openssl-filc, nghttp2-filc and curl-filc libraries and prepend their library directories to LD_LIBRARY_PATH. Host libraries are not ABI-compatible with Fil-C. No system library is replaced.
curl-filc builds pinned curl 8.22.0 sources with the native Fil-C compiler using upstream configure and make. The profile supports HTTP/HTTPS, HTTP/2, proxies and threaded DNS. It builds compatible OpenSSL 3.6.5 and nghttp2 1.70.0 dependencies; WebSockets and automatic content decoding remain disabled. HttpClient reports actual loaded-library features. OpenSSL also supplies Cryptography's optional runtime backend, without a link dependency in consumer libraries. Building these packages requires host make, patch, Perl and the usual configure prerequisites. OpenSSL uses the project-maintained Fil-C port rebase, retaining its assembly bridge. curl defaults to the Linux CA bundle /etc/ssl/certs/ca-certificates.crt; requests can supply a custom CA file. Cache identity includes source, compiler, port patch and relevant dependency identities. No system libraries are replaced.
The experimental Fil-C CI builds SCTest in Release and runs it through Support/Scripts/RunFilCTLSFixture.sh Release on every push and pull request, manual dispatch, and weekly on the default branch. Both native x86_64 and ARM64 are checked. Fil-C CI omits SaneHttpGet and single-file library compilation; those retain normal compiler coverage. Regular Linux CI uses Ubuntu 24.04 Debug and Ubuntu 26.04 Release; macOS retains both configurations. This native Linux fixture requires OpenSSL capabilities and exercises HttpClient's trusted custom CA, required HTTP/2 response, wrong CA and hostname rejection. Ordinary runs without fixture variables report an explicit transfer-test skip. Its public test-only credentials must never be used for a real service or installed into a system trust store. Functional ABI and protocol checks do not replace upstream OpenSSL tests or establish side-channel resistance.
repair is for a recognized existing layout whose current receipt or launcher metadata can be reconstructed. It is not a generic substitute for a failed install:
lock writes _Build/SC-package.lock, a local summary of installed receipts and exports:
The lock file makes a development environment auditable. It does not turn imported packages into content-addressed artifacts and should not be mistaken for an application dependency lock.
Use ./SC.sh package help for the current package catalog and action syntax. The registry and recipe API live in Tools/SC-package when an external tool needs to compose its own package entries.
SC::Format applies the repository's pinned clang-format configuration to supported source files.
Run this after editing C or C++ sources, then inspect the diff. Formatting does not decide whether generated files, comments, or declaration grouping are sensible.
check exits with an error when formatting would change a file, which makes it suitable for CI and pre-commit validation. Both actions use the package-managed formatter version expected by the repository.
The bootstrap keeps startup work incremental. It rebuilds ToolsBootstrap only when stale, locates the selected tool source, reuses unchanged Tools.cpp support objects, compiles the tool when needed, and then runs it with the original action and arguments.
ToolsBootstrap is deliberately small. The selected tool is linked with the Sane C++ unity build, so custom tools can use the libraries without maintaining another project definition. Build products remain below _Build/_Tools.
Use a tool for a bounded development operation with a command-line lifecycle. Use SC::Build for a graph of application targets. Use a library when behavior belongs in reusable program code. Keeping those roles separate prevents the bootstrap from becoming an application framework.