skip to content

How do you build Linux x64 and ARM64 executables of a Dart CLI from a macOS machine, and what limits apply?

level: seniorimportance: nice to knowfreq 18%

answer

  1. --target-os and --target-arch
  2. Linux is the only target OS
  3. arm64 and x64 since 3.8
  4. downloads extra binaries into ~/.dart
  5. macOS and Windows still need native hosts

basics

~10 s

Pass --target-os=linux and --target-arch=x64 or arm64 to dart compile exe or aot-snapshot. Since Dart 3.8 any 64-bit Linux, macOS or Windows host can cross-compile, but only to Linux targets.

solid answer

~40 s

`dart compile exe` and `dart compile aot-snapshot` accept `--target-os` and `--target-arch`. With `--target-os=linux --target-arch=arm64` (or `x64`), the tool downloads the target's `gen_snapshot` and `dartaotruntime` binaries, caches them under `~/.dart`, specialises `Platform` getters for Linux and produces a Linux binary. Linux ARM64 and x64 targets arrived in Dart 3.8; 32-bit `arm` and `riscv64` in 3.9. The target OS is limited to Linux, so macOS and Windows executables still have to be built on those systems - a release pipeline needs one macOS job, one Windows job, and can produce all Linux variants from any of them. An unsupported target makes the command fail with an 'Unsupported target platform' error. The usual `exe` limits still apply: no `dart:mirrors`, and packages with build hooks need `dart build` instead.

code

bash · 7 lines
bash
for arch in x64 arm64; do
  dart compile exe \
    --target-os=linux \
    --target-arch=$arch \
    bin/my_tool.dart \
    -o dist/my_tool-linux-$arch
done

go deeper

for a junior

Recall the two flags and that only Linux targets can be cross-compiled.

for a middle

Explain which architectures are supported since which release and what the tool downloads and caches.

for a senior

Design a release pipeline that builds macOS and Windows natively and every Linux variant by cross-compilation, with target-side testing.

for a principal

Weigh runner cost and coverage when deciding which platforms a CLI officially supports.

## Why cross-compilation matters AOT output is tied to an operating system and CPU architecture. Before Dart 3.8, shipping a CLI for Linux ARM64 servers meant finding a Linux ARM64 machine to build on. Cross-compilation removes that for Linux targets: a single developer machine or CI runner can produce binaries for several Linux architectures. ## The flags Both `dart compile exe` and `dart compile aot-snapshot` take two options: - **`--target-os`** - the operating system of the output. Only `linux` is supported as a cross target. - **`--target-arch`** - one of `arm` (32-bit ARM), `arm64`, `riscv64` (RV64GC) or `x64`. ``` dart compile exe --target-os=linux --target-arch=arm64 bin/my_tool.dart -o dist/my_tool-linux-arm64 ``` If the requested target equals the host, no cross-compilation happens. A target the tool cannot build makes it print `Unsupported target platform` and exit with an error. | Host (64-bit) | Linux ARM | Linux ARM64 | Linux RISCV64 | Linux x64 | |---|---|---|---|---| | Linux | yes | yes | yes | yes | | macOS | yes | yes | yes | yes | | Windows | yes | yes | yes | yes | ## What happens under the hood With `--verbose`, the command shows its steps: 1. **Download** the target-specific `gen_snapshot` and `dartaotruntime` binaries for the SDK version in use, and cache them in `~/.dart`. 2. **Specialise `Platform` getters** for the target OS, so `Platform.isLinux` reflects the target rather than the build host. 3. Generate the AOT kernel, then the AOT snapshot with the target's `gen_snapshot`. 4. Combine it with the target's runtime into an executable and mark it executable. The first build needs network access to fetch those binaries; later builds reuse the cache. CI caches should include `~/.dart` if runs are offline or frequent. ## Version history - **Dart 3.8** added cross-compilation to Linux ARM64 and x64. - **Dart 3.9** added Linux ARM (32-bit) and RISCV64. ## Scenario: a release pipeline for a CLI A tool shipped for macOS, Windows and Linux on two architectures needs: 1. a **macOS job** building the macOS executable - and, with cross-compilation, both Linux executables; 2. a **Windows job** building `my_tool.exe`, optionally code-signed; 3. an upload step collecting the artifacts. Without cross-compilation, the Linux ARM64 build would need its own ARM64 runner. ## Limits that still apply - **Linux only** as a cross target; macOS and Windows outputs need native hosts. - The general `exe` limits: no `dart:mirrors` or `dart:developer`. - **Build hooks**: packages with native assets must use `dart build`, which gained its own cross-compilation support later. - **32-bit x86 hosts** cannot run AOT compilation at all. - Test the output on the target: cross-compilation proves the binary builds, not that the tool's behaviour - file paths, shell commands, line endings - is right on Linux. ## Common mistakes - Expecting `--target-os=macos` or `windows` to work from another host. - Running the cross-compiled binary on the build machine to "test" it. - Forgetting that the first cross build downloads binaries and fails on an offline runner. - Branching on `Platform.isMacOS` at build time and being surprised the Linux binary takes the Linux branch.

  • Why does the first cross-compiled build need network access?
    The tool downloads the target-specific `gen_snapshot` and `dartaotruntime` binaries matching the SDK version and caches them in `~/.dart`. Later builds reuse the cache, so an offline CI runner needs that cache restored first.
  • What does Platform.isLinux return in a Linux binary cross-compiled on macOS?
    `true`. During cross-compilation the tool specialises `Platform` getters for the target OS, so the binary reports the platform it runs on, not the machine that built it.

saying these in an interview costs you the question

  • Thinks Dart can cross-compile a macOS executable on Linux
  • Believes cross-compilation works offline on a fresh machine
  • Expects the cross-compiled binary to run on the build host
  • Assumes a green cross-build proves the tool works on Linux
  • Thinks cross-compilation needs a separate Linux SDK install