Inspiration

QNX 8.0 is free for non-commercial use and QNX ships a Rust compiler for it. The first thing anyone porting Rust code asks is "will my dependencies build?", and nobody had an answer. The Rust ecosystem lives on crates.io, so the honest way to answer is to build crates.io: the most downloaded crates, with the exact toolchain QNX ships, on both QNX 8.0 targets.

What it does

QNX Crate Atlas is a Rust command line tool for Windows and Linux hosts plus a published dataset.

  • atlas doctor finds the QNX SDP 8.0 install, the QNX rustc, qcc and the license, and prints what the compiler reports for each target (target_os="nto", target_env="nto80").
  • atlas run builds each of the top 500 crates for x86_64-pc-nto-qnx800 and aarch64-unknown-nto-qnx800 inside a throwaway QNX binary that is linked with qcc, then records the first error of every failure and sorts it into a class that maps to a fix.
  • When libc breaks a build, it retries with libc pinned to 0.2.186, and atlas compat retries with our patched copies of libc, aws-lc-sys and target-lexicon.
  • atlas ontarget builds the unit tests of the top passing crates with the QNX toolchain and runs them on a QNX 8.0 kernel (QEMU with KVM inside WSL2).
  • atlas report publishes the matrix to https://qnx-crate-atlas.vercel.app: headline numbers per target, failure classes, the crates that block the most others, on-target test results, and a searchable table of every crate.
  • atlas probe <crate> checks any crate in one command.
  • atlas fix <project> applies the atlas's fixes to your own Cargo project: [patch.crates-io] entries for exactly the crates in your lockfile that need them (libc 0.2.189+, aws-lc-sys, target-lexicon), .cargo/config.toml settings for the QNX rustc 1.85 and the Windows qcc command-line limit, re-resolution if a dependency needs a newer rustc. It prints every change, keeps a backup of Cargo.toml, and verifies by building for both QNX 8.0 targets.

atlas fix on three real projects (outputs in examples/fix-demos): an axum 0.8 + tokio HTTP API (before: fails both targets in libc), a reqwest 0.13 + rustls client (before: a dependency needs rustc 1.88) and a clap + tracing + socket2 CLI (before: fails in libc) all build for x86_64 and aarch64 QNX 8.0 after one command. These were built, not run on the VM; crates with no known fix, such as nix, stay failing and are reported.

Results (QNX SDP 8.0 Rust toolchain, rustc 1.85.1, top 500 crates by all-time downloads, default features, November 2026):

Target Crates with a library Build out of the box + libc 0.2.186 pin + our patches Still fail
x86_64-pc-nto-qnx800 498 421 (84.5%) 459 (92.2%) 472 (94.8%) 26
aarch64-unknown-nto-qnx800 498 421 (84.5%) 459 (92.2%) 471 (94.6%) 27

A pass means the crate compiles for the target and links into a QNX executable that depends on it but does not call it. In one known case real use goes further: on aarch64, 4 crates that bring in aws-lc-rs through rustls (rustls, tokio-rustls, hyper-rustls, reqwest) pass the probe, but a program that actually uses rustls fails to link there (OPENSSL_cpuid_setup is undefined). Counting those 4 as failures, aarch64 with our patches is 467 (93.8%).

On a QNX 8.0 x86_64 kernel (QEMU/KVM), the unit tests of 19 of the top crates ran: 18 crates passed every test; 1,545 tests passed and 4 failed (all 4 in rustix, which reads its own source file src/buffer.rs, not copied to the VM).

The fixes (open source contributions)

  1. libc and the QNX target rename. Upstream Rust renamed the QNX 8.0 targets to target_os = "qnx"; libc 0.2.189+ follows the new name. The rustc QNX ships still says target_os = "nto", so the newest libc compiles none of its QNX 8 code. Pinning 0.2.186 recovers most crates, but that release lacks later QNX 8 definitions, which breaks socket2 and with it tokio networking, hyper clients, reqwest, axum and tonic. patches/make_libc_compat.py makes a compatibility copy of current libc (a build-script cfg plus a mechanical rewrite of 157 target_os predicates, no definitions changed). With it socket2 builds for both targets and TCP keepalive works on QNX 8.0, and tokio with every feature on (net included) builds for both targets and accepts a TCP connection on QNX 8.0 (examples/tokio-net).
  2. target-lexicon. It could not parse any QNX triple, so build scripts that read TARGET with it panicked (Invalid target name: 'x86_64-pc-nto-qnx800'), which blocked pyo3. Upstream pull request adding the QNX operating systems and environments: https://github.com/bytecodealliance/target-lexicon/pull/138
  3. aws-lc-rs (the default rustls crypto provider). Its C build used --include=, which qcc rejects, and needed _QNX_SOURCE for PTHREAD_RWLOCK_INITIALIZER and in6_addr. Upstream pull request, merged Nov 11 2026: https://github.com/aws/aws-lc-rs/pull/1292 . With it, a rustls binary builds and runs on QNX 8.0 x86_64. On aarch64 a program that uses rustls still failed to link (aws-lc's aarch64 CPU feature detection had no QNX variant); the fix reads the CPU features from the QNX system page and is open upstream as https://github.com/aws/aws-lc/pull/3780 . With it the binary links for aarch64 (not yet run on aarch64 hardware).

How we built it

Rust (clap, serde, ureq, toml) for the host tool; cargo's JSON diagnostics for classification; cargo's MSRV-aware resolver so every crate is tested at the newest version that supports rustc 1.85; a shared per-target build cache so common dependencies compile once; builds at idle priority, one at a time. The on-target stage boots a QNX 8.0 image made with mkqnximage under QEMU/KVM in WSL2, copies each test binary over SSH and parses libtest output. The page is static HTML and JavaScript over the published JSON.

Challenges we ran into

  • The QNX Rust package has no cargo; cargo 1.85.0 from rustup drives the QNX rustc through RUSTC.
  • WSL stops the VM when the wsl call that started it ends, so boot, test and shutdown happen in one call.
  • mkqnximage 0.5.0 builds images whose sshd dies at boot with OpenSSH 0.5.1 (/usr/libexec/sshd-auth missing); we patched the image build file locally.
  • cargo add libc writes libc = "0.2.191", which makes the 0.2.186 pin impossible; cargo add [email protected] avoids it.

Accomplishments that we're proud of

  • A measured answer for 500 crates on two targets with the shipping toolchain, with the first error of every failure.
  • Three fixes that each unblock a family of crates, two of them sent upstream as pull requests.
  • Crate test suites actually running on a QNX 8.0 kernel.
  • A codelab in the qnx.github.io format whose build commands are run by a script.

What we learned

QNX 8.0 Rust support is much better than its reputation: most failures are not about QNX at all but about one name change between the toolchain QNX ships and the one upstream ships. Fixing names and a few build flags matters more than porting code.

What's next

Run the Atlas on every QNX toolchain release and on the upstream x86_64-pc-qnx / aarch64-unknown-qnx targets, grow atlas fix as new fixes land, add aarch64 on-target tests on a Raspberry Pi 5, and send the libc compatibility idea to QNX and the libc maintainers with this data.

Built for QNX: where to verify

  • QNX toolchain handling: src/qnxenv.rs (atlas doctor)
  • Cross-compile and link with qcc for both QNX 8.0 targets: src/probe.rs
  • QNX failure classes: src/classify.rs (unit tested)
  • On-target tests on QNX 8.0: src/ontarget.rs, scripts/ontarget_session.sh
  • Raw results: data/results.jsonl, data/results-compat.jsonl, data/ontarget.jsonl
  • Fixes: patches/, examples proven on QNX 8.0: examples/

Build and run instructions

QNX version: QNX SDP 8.0 (non-commercial license). Toolchain: QNX Rust toolchain package com.qnx.qnx800.host.win.x86_64.rust (rustc 1.85.1) driven by cargo 1.85.0 from rustup, on a Windows 11 host. Targets: x86_64-pc-nto-qnx800 and aarch64-unknown-nto-qnx800 (build and link); on-target runs on QNX 8.0 x86_64 under QEMU/KVM in WSL2 Ubuntu 24.04, image from mkqnximage --type=qemu --arch=x86_64.

rustup toolchain install 1.85.0 --profile minimal
cargo build --release
target\release\atlas doctor
target\release\atlas probe tokio --target aarch64-unknown-nto-qnx800

Full steps are in the README; the codelab covers setting up the toolchain and the QEMU target from scratch.

Codelab

Rust on QNX 8.0 from a Windows Host: https://qnx-crate-atlas.vercel.app/codelab/

AI tools used

Claude (Anthropic) wrote the code, the patches, the codelab, this text and the video script at Matthew's direction; the video narration is local Piper text to speech. Every number comes from the published runs in data/.

Built With

Share this project:

Updates

Submission history