Using Nixpkgs in a Canadian cross configuration

Hi all! I’m wrestling with a situation in which something I’d like to package demands a Canadian cross compilation (the build, host, and target machines all differ from one-another). Presently, I understand how to use Nixpkgs in the simpler case where either build = host or host = target, as well as (I think) the use of pkgsXY in Nixpkgs and depsXY in stdenv (where X and Y are one of Build, Host, or Target). This leaves me feeling tantalizingly close to a solution, but I’m having a difficult time figuring out how to do this idiomatically.

I get the impression in some places that Nixpkgs wants to avoid the direct (build, host, target) situation by having the “sliding window” mentioned in the docs evolve along the following lines.

(build, build, build)
(build, build, host)
(build, host, host)
(host, host, host)
(host, host, target)

This seems plausible since you can then pluck the desired (host, target)-configured package from the last stage in that list (assuming you have a host system to use as a second build system, I think).

Unfortunately, my package depends extensively on others at build time which are not able to be built to run on host. In other words, it is critical that, at different times, the package be able to refer to all of the components of these triples, while all of them are different.

What I can’t figure out is how to use Nixpkgs to this effect. The depsXY construct used in packages are suggestive (to me) that this is an intended use, but how does one instantiate a Nixpkgs with a stdenv with differing buildPlatform, hostPlatform, and targetPlatform?

From what I’ve been able to discern, the Nixpkgs top-level limits you to specifying two systems: system/localSystem, and crossSystem, corresponding to the left and right side of the “sliding window” respectively. If those are set to platforms other than one’s own (what would be the build platform), no amount of sliding the window to the left (via buildPackages, pkgsBuildBuild, etc.) brings one back to the intended build system—Nixpkgs is stuck at what was meant to be host.

I do think I could hack a derivation together that builds the particular output that I’m interested in by instantiating Nixpkgs twice, one with crossSystem set to host, and one with it set to target, and then pulling what I need from each of those. Along these lines, I could perhaps extend pkgsCross with the needed platforms so that I can reference these packages from within a single Nixpkgs instantiation. Maybe slightly better would be to define a function that takes a target platform, and then after instantiating Nixpkgs with crossSystem set to host, pulling the desired package by passing target as the argument. I suppose I’m slightly worried that this is conceptually wrong and will come back to bite me somehow down the line.

The manual mentions:

Conversely if one wishes to cross compile “faster”, with a “Canadian Cross” bootstrapping stage where build != host != target, more bootstrapping stages are needed since no sliding window provides the pesky pkgsBuildTarget package set since it skips the Canadian cross stage’s “host”.

I’ve looked at the machinery handling stdenv’s bootstrapping stages, and the above makes me feel like there should be something I can do to manipulate these somehow to achieve the desired effect. The custom stage, for instance, takes a replaceStdenv attribute from config, which almost sounds like what I want, but I think it’s meant for other purposes.

Any ideas and input are much appreciated! Hoping to learn the idiomatic solution, if one exists, plus any other adjacent tricks that might prove useful in the future. :slight_smile:

1 Like