Home Explore Blog Models CI



nixpkgs

6th chunk of `doc/stdenv/cross-compilation.chapter.md`
df3df78bbcbaaf5f3f471c248ef8b631dd57da55db364612000000010000142d
#### What if my package’s build system needs to build a C program to be run under the build environment? {#cross-qa-build-c-program-in-build-environment}

Add the following to your `mkDerivation` invocation.

```nix
{ depsBuildBuild = [ buildPackages.stdenv.cc ]; }
```

#### My package’s testsuite needs to run host platform code. {#cross-testsuite-runs-host-code}

Add the following to your `mkDerivation` invocation.

```nix
{ doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform; }
```

#### Package using Meson needs to run binaries for the host platform during build. {#cross-meson-runs-host-code}

Add `mesonEmulatorHook` to `nativeBuildInputs` conditionally on if the target binaries can be executed.

e.g.

```nix
{
  nativeBuildInputs = [
    meson
  ]
  ++ lib.optionals (!stdenv.buildPlatform.canExecute stdenv.hostPlatform) [ mesonEmulatorHook ];
}
```

Example of an error which this fixes.

`[Errno 8] Exec format error: './gdk3-scan'`

#### Using `-static` outside a `isStatic` platform. {#cross-static-on-non-static-platform}

Add `stdenv.cc.libc.static` (static output of glibc) to `buildInputs` conditionally on if `hostPlatform` uses `glibc`.


e.g.

```nix
{
  buildInputs = lib.optionals (stdenv.hostPlatform.libc == "glibc") [ stdenv.cc.libc.static ];
}
```

Examples of errors which this fixes.

`cannot find -lm: No such file or directory`

`cannot find -lc: No such file or directory`

::: {.note}
At the time of writing, it is assumed the issue only happens on `glibc` because it splits the static libraries into a different output.

::: {.note}
You may want to look in to using `stdenvAdapters.makeStatic` or `pkgsStatic` or a `isStatic = true` platform.

## Cross-building packages {#sec-cross-usage}

Nixpkgs can be instantiated with `localSystem` alone, in which case there is no cross-compiling and everything is built by and for that system, or also with `crossSystem`, in which case packages run on the latter, but all building happens on the former. Both parameters take the same schema as the 3 (build, host, and target) platforms defined in the previous section. As mentioned above, `lib.systems.examples` has some platforms which are used as arguments for these parameters in practice. You can use them programmatically, or on the command line:

```ShellSession
$ nix-build '<nixpkgs>' --arg crossSystem '(import <nixpkgs/lib>).systems.examples.fooBarBaz' -A whatever
```

::: {.note}
Eventually we would like to make these platform examples an unnecessary convenience so that

```ShellSession
$ nix-build '<nixpkgs>' --arg crossSystem '{ config = "<arch>-<os>-<vendor>-<abi>"; }' -A whatever
```

works in the vast majority of cases. The problem today is dependencies on other sorts of configuration which aren't given proper defaults. We rely on the examples to crudely to set those configuration parameters in some vaguely sane manner on the users behalf. Issue [\#34274](https://github.com/NixOS/nixpkgs/issues/34274) tracks this inconvenience along with its root cause in crufty configuration options.
:::

While one is free to pass both parameters in full, there's a lot of logic to fill in missing fields. As discussed in the previous section, only one of `system`, `config`, and `parsed` is needed to infer the other two. Additionally, `libc` will be inferred from `parse`. Finally, `localSystem.system` is also _impurely_ inferred based on the platform evaluation occurs. This means it is often not necessary to pass `localSystem` at all, as in the command-line example in the previous paragraph.

::: {.note}
Many sources (manual, wiki, etc) probably mention passing `system`, `platform`, along with the optional `crossSystem` to Nixpkgs: `import <nixpkgs> { system = ..; platform = ..; crossSystem = ..; }`. Passing those two instead of `localSystem` is still supported for compatibility, but is discouraged. Indeed, much of the inference we do for these parameters is motivated by compatibility as much as convenience.
:::

One would think that `localSystem` and `crossSystem` overlap horribly with the three `*Platforms` (`buildPlatform`, `hostPlatform,` and `targetPlatform`; see `stage.nix` or the manual). Actually, those identifiers are purposefully not used here to draw a subtle but important distinction: While the granularity of having 3 platforms is necessary to properly *build* packages, it is overkill for specifying the user's *intent* when making a build plan or package set. A simple "build vs deploy" dichotomy is adequate: the sliding window principle described in the previous section shows how to interpolate between the these two "end points" to get the 3 platform triple for each bootstrapping stage. That means for any package a given package set, even those not bound on the top level but only reachable via dependencies or `buildPackages`, the three platforms will be defined as one of `localSystem` or `crossSystem`, with the former replacing the latter as one traverses build-time dependencies. A last simple difference is that `crossSystem` should be null when one doesn't want to cross-compile, while the `*Platform`s are always non-null. `localSystem` is always non-null.

Title: Cross-Packaging Cookbook: Static Linking and Nixpkgs Cross-Building Fundamentals
Summary
This chunk continues the 'Cross packaging cookbook,' first addressing how to use `-static` flags on non-static `glibc` platforms by conditionally adding `stdenv.cc.libc.static` to `buildInputs`. It also suggests alternatives like `stdenvAdapters.makeStatic` for static builds. The document then transitions to 'Cross-building packages,' explaining how Nixpkgs can be instantiated for cross-compilation using `localSystem` (the build system) and `crossSystem` (the target system). It provides examples of command-line usage with `nix-build` and notes that many fields for `localSystem` and `crossSystem` are inferred. The text clarifies the subtle but important distinction between `localSystem`/`crossSystem` (representing user intent for a build plan) and the more granular `buildPlatform`/`hostPlatform`/`targetPlatform` (necessary for actual package building), detailing how the former interpolate to define the latter.