From 0e825df6641f88354741ce5b5265d478c52e1c0a Mon Sep 17 00:00:00 2001 From: Ben Siraphob Date: Tue, 5 May 2026 00:05:04 -0700 Subject: [PATCH 1/2] doc/stdenv/cross-compilation: revamp and add emulation Q&A --- doc/redirects.json | 3 ++ doc/stdenv/cross-compilation.chapter.md | 42 ++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/doc/redirects.json b/doc/redirects.json index 3aead0a64e8d..2d4c8e8c62e0 100644 --- a/doc/redirects.json +++ b/doc/redirects.json @@ -1740,6 +1740,9 @@ "ssec-cross-cookbook": [ "index.html#ssec-cross-cookbook" ], + "cross-qa-emulation": [ + "index.html#cross-qa-emulation" + ], "cross-qa-fails-to-find-binutils": [ "index.html#cross-qa-fails-to-find-binutils" ], diff --git a/doc/stdenv/cross-compilation.chapter.md b/doc/stdenv/cross-compilation.chapter.md index 04159d93c57f..08e1a9bc22c7 100644 --- a/doc/stdenv/cross-compilation.chapter.md +++ b/doc/stdenv/cross-compilation.chapter.md @@ -2,7 +2,9 @@ ## Introduction {#sec-cross-intro} -"Cross-compilation" means compiling a program on one machine for another type of machine. For example, a typical use of cross-compilation is to compile programs for embedded devices. These devices often don't have the computing power and memory to compile their own programs. One might think that cross-compilation is a fairly niche concern. However, there are significant advantages to rigorously distinguishing between build-time and run-time environments! Significant, because the benefits apply even when one is developing and deploying on the same machine. Nixpkgs is increasingly adopting the opinion that packages should be written with cross-compilation in mind, and Nixpkgs should evaluate in a similar way (by minimizing cross-compilation-specific special cases) whether or not one is cross-compiling. +"Cross-compilation" means compiling a program on one machine for another type of machine. A typical use of cross-compilation is to compile programs for embedded devices that lack the computing power and memory to compile their own programs, but it is useful in many other contexts: producing trusted bootstrap artifacts on Hydra for platforms without physical build hardware, using fast machines (e.g. x86_64) to build for slower architectures popular in routers and switches (e.g. mips/powerpc), and rigorously distinguishing build-time from run-time environments even when developing and deploying on the same machine. Nixpkgs adopts the opinion that packages should be written with cross-compilation in mind, and Nixpkgs should evaluate in a similar way (by minimizing cross-compilation-specific special cases) whether or not one is cross-compiling. + +For a hands-on tutorial, see the [cross-compilation guide on nix.dev](https://nix.dev/tutorials/cross-compilation). This chapter will be organized in three parts. First, it will describe the basics of how to package software in a way that supports cross-compilation. Second, it will describe how to use Nixpkgs when cross-compiling. Third, it will describe the internal infrastructure supporting cross-compilation. @@ -70,6 +72,8 @@ The exact schema these fields follow is a bit ill-defined due to a long and conv : This is, quite frankly, a dumping ground of ad-hoc settings (it's an attribute set). See `lib.systems.platforms` for examples—there's hopefully one in there that will work verbatim for each platform that is working. Please help us triage these flags and give them better homes! +Using these attributes, the build process of a package can change depending on the situation. + ### Theory of dependency categorization {#ssec-cross-dependency-categorization} ::: {.note} @@ -131,6 +135,42 @@ software floating point emulation. `libgcc` would be a "target→ *" dependency Some frequently encountered problems when packaging for cross-compilation should be answered here. Ideally, the information above is exhaustive, so this section cannot provide any new information, but it is ludicrous and cruel to expect everyone to spend effort working through the interaction of many features just to figure out the same answer to the same common problem. Feel free to add to this list! +#### How do I test cross-compilation using emulation? {#cross-qa-emulation} + +Every elaborated platform exposes an `emulator` function on its `hostPlatform` attribute that returns the path to an emulator capable of running binaries for that platform. The dispatch is defined in `lib/systems/default.nix` and selects: + +- a no-op exec wrapper, when the build platform can already execute the host platform's binaries +- `wine` for Windows targets +- `qemu-user` for foreign Linux targets on a Linux builder +- `wasmtime` for WASI +- `nodejs-slim` for GHCJS +- `mmix` for MMIX + +`emulator` is a function of the package set; `emulatorAvailable` is a predicate of the same shape that reports whether an emulator exists. Use them from a `nix` expression rather than invoking `qemu` by hand, for example inside a `checkPhase` or `passthru.tests` derivation: + +```nix +stdenv.mkDerivation { + # ... + doCheck = stdenv.hostPlatform.emulatorAvailable buildPackages; + checkPhase = '' + ${stdenv.hostPlatform.emulator buildPackages} ./my-binary --self-test + ''; +} +``` + +To run a cross-compiled binary outside the Nix sandbox, build it and invoke the emulator from a shell. This is also a quick way to verify the dispatch table above: + +```ShellSession +$ nix-build '' -A pkgsCross.aarch64-multiplatform.hello +$ nix-instantiate --eval --strict -E \ + '(import { crossSystem.config = "aarch64-unknown-linux-gnu"; }).stdenv.hostPlatform.emulator (import {})' +"/nix/store/.../bin/qemu-aarch64" +$ nix-shell -p qemu --run 'qemu-aarch64 ./result/bin/hello' +Hello, world! +``` + +The same pattern works for other targets by substituting the `pkgsCross.*` attribute and the emulator package (e.g. `wine` for `pkgsCross.mingwW64`). + #### My package fails to find a binutils command (`cc`/`ar`/`ld` etc.) {#cross-qa-fails-to-find-binutils} Many packages assume that an unprefixed binutils (`cc`/`ar`/`ld` etc.) is available, but Nix doesn't provide one. It only provides a prefixed one, just as it only does for all the other binutils programs. It may be necessary to patch the package to fix the build system to use a prefix. For instance, instead of `cc`, use `${stdenv.cc.targetPrefix}cc`. From 1fdac5afd2d1edeb11c2530cf95f4f30529f7cdc Mon Sep 17 00:00:00 2001 From: Doron Behar Date: Tue, 5 May 2026 11:17:23 +0300 Subject: [PATCH 2/2] doc/stdenv/cross-compilation: expand a bit emulation example --- doc/stdenv/cross-compilation.chapter.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/stdenv/cross-compilation.chapter.md b/doc/stdenv/cross-compilation.chapter.md index 08e1a9bc22c7..18f3b2344607 100644 --- a/doc/stdenv/cross-compilation.chapter.md +++ b/doc/stdenv/cross-compilation.chapter.md @@ -161,10 +161,20 @@ stdenv.mkDerivation { To run a cross-compiled binary outside the Nix sandbox, build it and invoke the emulator from a shell. This is also a quick way to verify the dispatch table above: ```ShellSession -$ nix-build '' -A pkgsCross.aarch64-multiplatform.hello +$ nix-build '' -A pkgsCross.aarch64-multiplatform.hello # Should be available in cache.nixos.org +``` + +To get a path for an emulator, given a `crossSystem.config` (e.g with `aarch64-linux`): + +```ShellSession $ nix-instantiate --eval --strict -E \ '(import { crossSystem.config = "aarch64-unknown-linux-gnu"; }).stdenv.hostPlatform.emulator (import {})' "/nix/store/.../bin/qemu-aarch64" +``` + +And specifically for `aarch64-linux`, and many other platforms, you have all of them available in `qemu` package, meaning you can simply run: + +```ShellSession $ nix-shell -p qemu --run 'qemu-aarch64 ./result/bin/hello' Hello, world! ```