MMotor OS
Developing

Toolchains

Motor OS has one compilation target, x86_64-unknown-motor, and two toolchains for it. On Linux, a cross toolchain (Rust with Cargo, and Clang) builds Motor OS itself and any program for it. On the developer image, a native toolchain (rustc with a full sysroot, Clang/LLVM with a C and C++ sysroot, and Lorry as the build driver) builds programs on Motor OS. Both come from the same forks of Rust, LLVM, and mlibc.

Components and lineage

ComponentSourceWhat Motor OS adds
Rustmoturus/rust, based on the upcoming Rust release (1.99 at the time of writing) with LLVM 23The x86_64-unknown-motor target, a Tier-3 target upstream; the standard library's Motor OS layer, which calls the moto-rt crate (0.17.x); a few compiler patches, all on one development branch per upstream baseline (motor-os-1.99.0-beta-f47d5bb today), from which both the cross and the native toolchain are built.
Cargo, Clippy, rustfmtUpstream, at the revisions the Rust fork specifiesNothing; they run on Linux only.
LLVMmoturus/llvm-project, LLVM 23A Motor OS target in Clang: the driver knows the link line, the defaults (emulated TLS, static PIE, lld, compiler-rt, libc++), and the sysroot layout. Built twice: for the Linux host, and natively for Motor OS.
mlibcmoturus/mlibcThe Motor OS sysdeps and a build configuration that reads its runtime files from /system/cfg/libc. It sits on moto-rt-cabi, a C ABI over the Motor runtime (see C/C++ on Motor OS).
Small crate forksmoturus/libc, moturus/stacker, moturus/rust_libloading, moturus/rust-ctrlcPatched into the Rust fork's own dependency graph; Cargo fetches them, nothing is cloned by hand.
Lua, ripgrepLua 5.4.8 from lua.org, unmodified; moturus/ripgrepBuilt with the toolchain as the first real C program and the first large Rust program; shipped as /devtools/bin/lua and /system/bin/rg.

The target

The target specification in the Rust fork describes what every Motor OS program looks like: a static position-independent executable, linked self-contained (no dynamic linking, no system linker libraries), panic = abort, entry point motor_start, thread-locals provided by the runtime rather than ELF TLS, and full RELRO. Clang's Motor target applies the same rules to C and C++: emulated TLS, -static-pie, lld, and a link line that adds crt1.o, the runtime shim, libc++abi, libunwind, libc, and the compiler builtins. A program built by either compiler runs on any Motor OS image, because it carries everything it needs except the runtime object that the OS maps into every process.

The cross toolchain on Linux

Rust

The Motor OS build installs the Rust fork's output as one rustup toolchain whose name carries the upstream baseline and a key derived from every input, motor-1.99.0-beta-f47d5bb-dev.1-<key> today. It contains rustc and rustdoc, its own Cargo, Clippy, and rustfmt, the standard library for the Linux host, the standard library for x86_64-unknown-motor under lib/rustlib/x86_64-unknown-motor, and the library sources; nothing is borrowed from another rustup channel. The repository's rust-toolchain.toml names that exact toolchain, so everything in the repository is built with

cargo build --target x86_64-unknown-motor [--release]

and nothing more: the standard library is prebuilt, so ordinary programs do not use -Zbuild-std. Only the bare-metal pieces, the kernel and the boot stages, use custom JSON targets and build core and alloc themselves from the toolchain's library sources. The Makefile applies the same command to every component, keeps each crate's Cargo output under build/obj/<toolchain-key>/, and copies stripped binaries into build/bin/debug or build/bin/release for the imager; make -j$(nproc) builds the debug tree and BUILD=release the release tree. See Building Motor OS.

A pure-Rust program needs no linker configuration: rustc links it with its bundled lld. A crate that compiles C code (curl, Lorry) points Cargo at the Motor Clang instead, with CARGO_TARGET_X86_64_UNKNOWN_MOTOR_LINKER set to motor-clang (from the selected assembly's sysroot/bin) and CC_x86_64_unknown_motor to the same compiler, so that the C parts are built against the Motor sysroot.

Cross-compiling your own program

  1. cargo new hello, and write the program against the standard library, as on any other platform.
  2. If it uses Tokio, mio, rustls with ring, crossterm, or the ctrlc crate, add the Motor OS forks to [patch.crates-io] in Cargo.toml, as the in-tree programs do; the table in Rust on Motor OS lists them.
  3. cargo build --release --target x86_64-unknown-motor. The repository's rust-toolchain.toml applies to projects inside the checkout (the recipe uses build/examples/); for a project elsewhere, copy that file next to its Cargo.toml. The result is target/x86_64-unknown-motor/release/hello.
  4. Copy it into a running VM with scp and run it; see Hello Motor OS for the whole sequence.

C and C++

The host Clang is the LLVM fork's own build, with a configuration file next to it that turns every link for x86_64-unknown-motor into a raw static-PIE link (-fuse-ld=lld -static-pie -nostdlib -Wl,-e,motor_start); that raw form is what the build uses to construct the sysroot itself. For compiling programs, the build also produces, under the selected assembly ($MOTORH/assemblies/<key>/sysroot), a sysroot directory with mlibc's headers and the static libraries, and three small wrappers in its bin:

WrapperWhat it does
motor-clangRuns the host Clang with --target=x86_64-unknown-motor and the sysroot, letting the driver's Motor target add the runtime link line; motor-clang -O2 prog.c -o prog is a complete build.
motor-clang++The same for C++, with libc++.
motor-rust-ccThe linker Cargo uses for Rust crates with C parts: adds the runtime group (crt1.o, the shim, libc++, libc++abi, libunwind, libc, the builtins) to a rustc-driven link.

A C program cross-compiled this way is the same static executable the native compiler produces, and runs on any image. What the C library and libc++ support is on the C/C++ on Motor OS page.

The native toolchain on the developer image

Nothing on the developer image compiles itself into existence: the native compilers are cross-built on Linux and staged into the image. Once there, they compile Motor OS programs on Motor OS, with no host involved.

rustc

/devtools/rust/bin/rustc is the Rust fork's compiler built with Motor OS as the host (x.py build --stage 2 compiler --host x86_64-unknown-motor): a single static executable of about 100 MB with its own LLVM inside. Its sysroot, /devtools/rust/lib/rustlib/x86_64-unknown-motor/lib, is the complete set of prebuilt crates: std, core, alloc, proc_macro, test, panic_abort, the compiler builtins, moto_rt, and their dependencies, each as an .rlib with its metadata. /devtools/bin/rustc, the command on PATH, is a two-line script that sets TMPDIR=/devtools/tmp and runs it.

rustc -O hello.rs -o /devtools/tmp/hello && /devtools/tmp/hello

No linker option is needed: rustc's default linker driver is cc, which on the image is /devtools/bin/cc, the native Clang, which links with lld. There is no Cargo, Clippy, rustfmt, or rustdoc on the image; packages with dependencies are built with Lorry, below, which also runs procedural macros as separate static executables because Motor OS has no dynamic loading.

Clang/LLVM

/devtools/llvm/bin/llvm is one static executable of about 107 MB that contains the whole LLVM toolchain as subcommands: clang, clang++, lld (and its ld.lld flavor), ar, ranlib, nm, objcopy, strip, objdump, readelf, size, addr2line, cxxfilt, dwp, and more, invoked as llvm clang ... or llvm ar .... It was configured with Motor OS as its host and default target, lld as the default linker, compiler-rt as the runtime library, libc++ as the C++ standard library, and /devtools/cfg/llvm as its configuration directory, where x86_64-unknown-motor.cfg points it at its resource directory, /devtools/llvm/lib/clang/23. /devtools/bin/cc and /devtools/bin/c++ are two-line scripts over it.

The sysroot is under /devtools/llvm: include holds mlibc's headers, libc++'s c++/v1, and moto_rt.h; lib holds crt1.o, libc.a, libc++.a, libc++abi.a, libunwind.a, libmoto_rt_cabi.a, the compiler-rt builtins, and empty libm, libpthread, libdl, librt, libresolv, libutil, and libssp archives so that -lm and friends in existing build systems link. The C library reads its runtime files from /system/cfg/libc.

Lorry

Lorry is the Rust build driver on the image, and a smaller, stricter Cargo replacement for security-sensitive environments: it takes the same Cargo.toml and Cargo.lock and aims for byte-identical binaries, never invokes Cargo, admits dependencies once and explicitly with lorry vendor, and then builds, runs, and tests packages offline using /devtools/bin/rustc and, for crates with C parts, /devtools/bin/cc and llvm ar. It builds red and itself natively in the developer-image test. It has its own page: Lorry: the package manager.

lorry new hello && cd hello
lorry vendor --accept-all      # once, with network access
lorry build --release
lorry run

Also on the image

/devtools/bin/lua (Lua 5.4.8), /system/bin/curl (the HTTPS client Lorry fetches with), /devtools/bin/mdbg, the test suites under /devtools/tests, and source snapshots under /devtools/src; see Developer image.

How the pieces are produced

The build script (src/build-motor-os.sh) produces everything above in a fixed order, on Ubuntu, in one to two hours, from the exact source revisions declared in src/toolchain-versions.sh. The order matters because each layer is built with the one before it:

  1. The Rust and mlibc forks are checked out at their declared commits; LLVM and Cargo come in as the Rust checkout's submodules, so one LLVM tree serves every LLVM build.
  2. The host Clang and lld are built from that LLVM tree.
  3. One x.py run from the Rust fork builds and installs the cross toolchain: rustc, rustdoc, Cargo, Clippy, rustfmt, both standard libraries, and the library sources, into an immutable directory named by its key, which is registered with rustup. Every later step and every Motor OS component uses it.
  4. The runtime shim (moto-rt-cabi) is built with the cross toolchain, then the compiler-rt builtins, then mlibc against the shim, then libunwind, libc++abi, and libc++ against mlibc.
  5. The native LLVM multicall binary is built for Motor OS against that sysroot, and Lua is cross-compiled against the same sysroot as a check that a real C program links and runs.
  6. A second x.py run from the same Rust revision produces the native rustc with Motor OS as host; the installed cross toolchain is verified to be unchanged by it.
  7. The results are staged under $MOTORH/assemblies/<key>/images/, with the manifest, from which the imager places them into the developer image.

The steps are listed so the relationships are clear; the procedure, the directory layout, and the test suites are on the Building Motor OS page.

Versioning

The toolchain is defined by source revisions, not by branch tips: one file in the repository, src/toolchain-versions.sh, declares the upstream Rust release and commit, the LLVM commit that release uses, the Motor Rust and LLVM commits on top of them, the Cargo and mlibc commits, and the moto-rt version. Every version change is a reviewed diff to that file; a normal build never advances a branch or runs cargo update.