A toolchain manager for C++. Inspired by rustup.
| Platform | Status |
|---|---|
| macOS ARM64 (Apple Silicon) | Supported |
| Linux x86_64 | Supported |
| Linux ARM64 | Supported |
| Windows x86_64 (MSVC) | Supported |
macOS / Linux:
curl -fsSL https://raw.githubusercontent.com/misut/intron/main/install.sh | shWindows (PowerShell):
iwr -useb https://raw.githubusercontent.com/misut/intron/main/install.ps1 | iexmise install "vfox:misut/mise-intron@latest"
mise use "vfox:misut/mise-intron@latest"Requires exon and a C++23 toolchain with
import std; support (clang with libc++ modules).
# macOS and Linux — self-host with intron:
curl -fsSL https://raw.githubusercontent.com/misut/intron/main/install.sh | sh
git clone git@github.com:misut/intron.git && cd intron
intron install
eval "$(intron env)"
exon build --releaseThe Linux self-host flow relies on the share/libc++/v1/std.cppm module
that ships in the official LLVM-<version>-Linux-X64.tar.xz tarball,
together with the -stdlib=libc++ / rpath flags that
intron install llvm writes into etc/clang/<target>.cfg. No
distribution-level libc++ package is required.
The binary will be at .exon/release/intron.
From a regular PowerShell session:
iwr -useb https://raw.githubusercontent.com/misut/intron/main/install.ps1 | iex
git clone https://github.com/misut/intron
cd intron
intron installWith the repo's .intron.toml, intron install will:
- reuse a compatible Visual Studio 2022 / Build Tools 2022 instance when one already exists
- modify an existing Visual Studio 2022 instance to add the C++ workload when needed
- install a dedicated Build Tools 2022 instance when no compatible instance exists
Use intron env to export the resolved environment into the current shell, or
intron exec -- <command> [args...] to run a one-off command with the same
resolved variables:
Invoke-Expression ((intron env) -join "`n")Once that environment is active, you can bootstrap intron itself from a normal shell:
git clone https://github.com/misut/tomlcpp --branch v0.3.0
git clone https://github.com/misut/cppx --branch v1.12.0
cmake -G Ninja -S .github/cmake -B build `
-DCMAKE_BUILD_TYPE=Release `
-DTOMLCPP_DIR=..\tomlcpp `
-DCPPX_DIR=..\cppx
cmake --build build
.\build\intron.exe helpOr keep the current shell untouched and run the same flow through intron exec:
git clone https://github.com/misut/tomlcpp --branch v0.3.0
git clone https://github.com/misut/cppx --branch v1.12.0
intron exec -- cmake -G Ninja -S .github/cmake -B build `
-DCMAKE_BUILD_TYPE=Release `
-DTOMLCPP_DIR=..\tomlcpp `
-DCPPX_DIR=..\cppx
intron exec -- cmake --build build
intron exec -- .\build\intron.exe helpRequirements: Windows x64, Visual Studio 2022 channel support, CMake 3.30+, Ninja.
When msvc is selected as the default toolchain on Windows, intron env prints a full developer environment instead of just CC and CXX:
intron install msvc 2022
intron default msvc 2022 --platform windows
intron envThe output includes:
$env:PATHwith the MSVCHostx64/x64bin directory$env:PATHalso gets the installed Windows 10/11 SDKbin/<version>/<arch>directory sorc.exe,mt.exe, andsigntool.exeresolve without a separately-opened developer shell$env:CC/$env:CXXpointing tocl.exe$env:INCLUDE,$env:LIB, and$env:LIBPATHfromvcvars64.bat
The highest installed Windows SDK is picked by default. To pin a specific version, add it under [toolchain.windows] in .intron.toml:
[toolchain.windows]
msvc = "2022"
sdk = "10.0.26100.0"This is intended to make direct execution of MSVC-built tools and Windows ASan binaries work from a regular PowerShell session, not just from a pre-opened Visual Studio developer shell.
intron exec -- <command> [args...] uses the same resolved MSVC-related variables and injects them directly into the child process environment, so commands such as cl.exe and exon test can run without manually eval-ing the shell output first.
On Windows, compiler selection now follows the effective defaults after project and global config are merged:
- If
msvcis configured,intron env/intron execusecl.exeforCCandCXX. - If
msvcis not configured andllvmis configured, they useclang-cl.exe. - Installed LLVM tools still stay on
PATH, even whencl.exeis selected.
Before this change, a mixed configuration such as project [toolchain] llvm = "22.1.2"
plus global [defaults.windows] msvc = "2022" still selected clang-cl.exe for
CC / CXX. That older hybrid mode no longer happens implicitly. If you still want
it, override CC and CXX manually after intron env or before intron exec.
This is why a repository such as phenotype could differ between local Windows and
GitHub Actions Windows CI:
- Local Windows: the repo's common
.intron.tomlkeptllvm, and the user's~/.intron/config.tomladded[defaults.windows] msvc = "2022", sointron envmerged both sources into one effective Windows toolchain set. - GitHub Actions Windows CI: the workflow used
ilammy/msvc-dev-cmd@v1and then setCC=cl/CXX=cldirectly, which bypassed intron's compiler selection logic.
intron install llvm 22.1.2
intron install cmake 4.3.1
intron install ninja 1.13.2
intron default llvm 22.1.2
intron default cmake 4.3.1
intron default ninja 1.13.2
eval "$(intron env)"
clang++ --version
intron exec -- cmake --version
intron exec -- exon testOn Windows PowerShell, use Invoke-Expression ((intron env) -join "n")instead ofeval "$(intron env)"`.
Human-facing commands use compact stage and status lines. Long-running
installation work is grouped by tool and phase, while intron status and
intron doctor use small capability-aware section accents plus a readiness
summary so toolchain, environment, diagnostics, and terminal details are easier
to scan. Script-oriented commands such as intron env, intron which, and
intron exec -- ... keep their machine-readable output unchanged.
Set INTRON_COLOR=auto|always|never to control ANSI color in human output.
NO_COLOR=1 disables color in auto mode, while FORCE_COLOR=1 enables color
unless NO_COLOR is also set. intron status and intron doctor include a
summary plus terminal capability details so CI/non-TTY output explains why live
styling is or is not active.
intron env supports two additive output modes for cases where the default
shell-eval form is unwanted (for example, GitHub Actions, where reassigning
PATH via Invoke-Expression would freeze it at eval time and mask later
$GITHUB_PATH updates).
-
intron env(default) — shell-eval form (export KEY="..."or$env:KEY = "..."). Intended foreval "$(intron env)"/Invoke-Expression. Unchanged from previous releases. -
intron env --path-only(aliasintron env --additive) — emits every segment intron would prepend toPATH, one directory per line, with no quoting and no variable references. Non-PATHvariables are suppressed. Pipe directly into$GITHUB_PATHon GitHub Actions:intron env --path-only | ForEach-Object { $_ >> $env:GITHUB_PATH }
-
intron env --github— emitspath=<dir>for everyPATHsegment andenv=<KEY>=<value>for every other variable. Route the two streams with a single-pass switch:intron env --github | ForEach-Object { if ($_ -match '^path=(.+)$') { $matches[1] >> $env:GITHUB_PATH } elseif ($_ -match '^env=(.+)$') { $matches[1] >> $env:GITHUB_ENV } }
intron exec -- <command> is unaffected; it always injects the resolved
variables directly into the child process environment.
intron commands [--output human|json] exposes the command registry used by
the built-in completion engine. intron complete [--output human|json|raw] -- [words...] prints candidates for a partial invocation, and intron completion bash|zsh|fish emits shell completion scripts that call that same command at
completion time.
| Command | Description |
|---|---|
intron install [tool] [version] |
Install toolchain(s) (reads .intron.toml if no args) |
intron remove <tool> <version> |
Remove an installed toolchain |
intron list |
List installed toolchains |
intron which <binary> |
Print absolute path to a binary |
intron default <tool> <version> [--platform <name>] |
Set global default version |
intron use [tool] [version] [--platform <name>] |
Set project toolchain in .intron.toml |
intron env [--path-only|--github] |
Print environment variables (eval "$(intron env)" or PowerShell Invoke-Expression ((intron env) -join "n")`) |
intron exec -- <command> [args...] |
Run a command with the resolved intron environment |
intron commands [--output human|json] |
Describe command metadata |
intron complete [--output human|json|raw] -- [words...] |
Print completion candidates |
intron completion bash|zsh|fish |
Generate a shell completion script |
intron update [tool] |
Check for newer versions |
intron upgrade [tool] |
Upgrade tools to latest |
intron self-update |
Update intron itself |
intron help |
Show usage information |
For MSVC on Windows, intron install msvc 2022 keeps its provisioning role: it
ensures that a compatible Visual Studio 2022 / Build Tools 2022 instance has the
C++ workload and can be used by intron env / intron exec.
Use intron update msvc to compare the single MSVC instance currently selected by
intron against that instance's configured update channel, and intron upgrade msvc
to apply the available servicing update to that same selected instance.
| Tool | Source | Binaries |
|---|---|---|
| LLVM | llvm/llvm-project | clang, clang++, lld, lldb, ... |
| CMake | Kitware/CMake | cmake, ctest, cpack |
| MSVC | Visual Studio 2022 / Build Tools 2022 | cl.exe, link.exe, vcvars64.bat (system tool) |
| Ninja | ninja-build/ninja | ninja |
| wasi-sdk | WebAssembly/wasi-sdk | WASI cross-compiler (via $WASI_SDK_PATH) |
| wasmtime | bytecodealliance/wasmtime | wasmtime |
wasi-sdk is exposed via the WASI_SDK_PATH environment variable (not PATH) to avoid
conflicts with the native LLVM clang.
intron install wasi-sdk 32
intron default wasi-sdk 32
eval "$(intron env)"
echo $WASI_SDK_PATH
$WASI_SDK_PATH/bin/clang --sysroot=$WASI_SDK_PATH/share/wasi-sysroot hello.c -o hello.wasm
# Or via the bundled CMake toolchain file:
cmake -DCMAKE_TOOLCHAIN_FILE=$WASI_SDK_PATH/share/cmake/wasi-sdk.cmake ...- Download caching — archives are cached in
~/.intron/downloads/and reused on reinstall - Checksum verification — SHA-256 verification for tools that provide checksums (CMake)
- Atomic installs — extracts to staging directory, then atomically renames to final path
- Project config — pin toolchain versions per project with
.intron.toml - Auto clang config — generates clang configuration files on macOS for SDK and libc++ setup
Use intron use to generate .intron.toml from current defaults:
intron use # pin all defaults
intron use llvm 22.1.2 # pin specific tool
intron use msvc 2022 --platform windows
intron install # install all from .intron.tomlFor shared repositories, keep portable tools in [toolchain] and put platform-only
tools under [toolchain.<platform>]. intron use without arguments preserves that
layout when your defaults already use platform sections.
This creates .intron.toml in the current directory:
[toolchain]
cmake = "4.3.1"
ninja = "1.13.2"
[toolchain.macos]
llvm = "22.1.2"
[toolchain.linux]
llvm = "22.1.2"
[toolchain.windows]
msvc = "2022"Project config is used by install (when called without args), which, env,
exec, list, and update.
~/.intron/
├── config.toml # default versions
├── downloads/ # cached archives
└── toolchains/
├── llvm/22.1.2/bin/clang++
├── cmake/4.3.1/bin/cmake
├── ninja/1.13.2/ninja
└── wasi-sdk/32/bin/clang
MIT