# Toolchains

Choose the cross-compiler that builds the firmware. hpx builds through
neuralSPOT-X, which supports three Cortex-M toolchains; the choice changes
build time, binary size and cycle counts, so hold the model, engine and target settings fixed when comparing compilers.
Supported combinations depend on the engine and board.

## Prerequisites

At least one toolchain installed and found by `hpx doctor`
([Install](https://ambiqai.github.io/helia-profiler/getting-started/install/) covers GCC). Arm Compiler 6
needs a licence; ATfE needs `ATFE_ROOT`.

## Which toolchain

| `target.toolchain` | Compiler | Linker | Cost to set up | Pick it when |
|---|---|---|---|---|
| `arm-none-eabi-gcc` (default; `gcc` is the accepted alias) | GNU Arm Embedded | GNU `ld` | free; install a supported host package | First setup, CI without a licence, cross-platform reproducibility. The default heliaRT registry module builds with it. |
| `armclang` | Arm Compiler 6 | `armlink` | licence required | Cycle-count optimisation on Cortex-M55, or confirming a result replicates across compilers. Not covered by ExecuTorch validation. |
| `atfe` | Arm Toolchain for Embedded (LLVM) | LLD | free download, `ATFE_ROOT` | An open LLVM toolchain; preview status in hpx. Builds the heliaRT registry flow and ExecuTorch end to end. |

The four accepted values are the `Toolchain` vocabulary in
`src/helia_profiler/vocab.py`: `arm-none-eabi-gcc`, `gcc`, `armclang`,
`atfe`. Arm Compiler 5 is not among them and is not supported; there is no
flag or key for it.

## Steps

### 1. Select it

```bash
hpx profile model.tflite --toolchain armclang
```

```yaml
target:
  toolchain: armclang
```

The selection flows to `nsx configure --toolchain`. GCC is the special
case: when `arm-none-eabi-gcc` or `gcc` is selected hpx omits the flag so
neuralSPOT-X uses its default GCC configuration; `armclang` and `atfe` are
passed through. Binary sections are probed with `arm-none-eabi-size` for
GCC, `fromelf` for Arm Compiler 6 and `llvm-size` from `ATFE_ROOT/bin` for
ATfE.

### 2. Install the one you chose

Install as on [Install](https://ambiqai.github.io/helia-profiler/getting-started/install/#2-arm-gnu-toolchain),
then verify:

```bash
arm-none-eabi-gcc --version
arm-none-eabi-size --version
```

`armclang` ships with
[Arm Development Studio](https://developer.arm.com/Tools%20and%20Software/Arm%20Development%20Studio)
or the standalone Arm Compiler for Embedded, under licence:

```bash
export PATH="/path/to/ArmCompilerForEmbedded/<version>/bin:$PATH"
export ARMLMD_LICENSE_FILE="<port>@<server>"   # or an offline licence file
armclang --version
fromelf --version
```

`armclang --version` works without consuming a licence; the build fails at
the first compile if the licence server is unreachable.

Download from
[developer.arm.com](https://developer.arm.com/downloads/-/arm-toolchain-for-embedded)
and set `ATFE_ROOT` to the extracted toolchain root, not its `bin/`:

```bash
export ATFE_ROOT="/path/to/atfe/<version>"
"$ATFE_ROOT/bin/clang" --version
"$ATFE_ROOT/bin/llvm-size" --version
```

hpx expects `clang`, `clang++`, `llvm-ar`, `llvm-objcopy`, `llvm-size` and
`llvm-nm` under `$ATFE_ROOT/bin`.

### 3. Compare on your own model

Compiler results depend on the model, the engine, the optimisation settings
and the clock, so measure rather than assume. Same model, three
toolchains, three directories:

```bash
hpx profile model.tflite --toolchain gcc      --output-dir results/gcc
hpx profile model.tflite --toolchain armclang --output-dir results/armclang
hpx profile model.tflite --toolchain atfe     --output-dir results/atfe
hpx compare results/gcc results/armclang
```

The work directory is not shared between toolchains; each run configures
and builds from scratch. Hold the engine, board and counters constant and
vary only `--toolchain`, otherwise a cycle delta could be any of them. The
[toolchain comparison example](https://ambiqai.github.io/helia-profiler/examples/toolchain-comparison/) is
that recipe with captured output.

## Expected output

`run_metadata.json` records the resolved toolchain and the compiler
version it found; the terminal report's memory table names the size tool
used. Different toolchains produce different cycle counts for the same
model, which is the point of measuring.

## Troubleshooting

:::caution[`armclang: command not found`]
The Arm Compiler `bin/` directory is not on `PATH`. Source the setup script
that ships with Arm Development Studio, or add the path.
:::

:::caution[`License checkout failed (-15)`]
Set `ARMLMD_LICENSE_FILE` to the licence server or file. The version check
passes without a licence; the compile step does not.
:::

:::caution[`ATFE_ROOT` is missing or incomplete]
Point `ATFE_ROOT` at the extracted root, not `bin/`, and confirm
`$ATFE_ROOT/bin/clang` and `$ATFE_ROOT/bin/llvm-size` exist.
:::

:::caution[Different cycle counts on different toolchains]
Expected: the compiler is one of the variables that decide code generation.
Isolate it by holding everything else constant.
:::

## What next

[Capture transports](https://ambiqai.github.io/helia-profiler/guide/transports/) for how the data leaves the board, or
[Engines](https://ambiqai.github.io/helia-profiler/guide/engines/) if the engine you want constrains the toolchain
(ExecuTorch is validated on GCC and ATfE).
