Cross Compiling: Difference between revisions

Frontear (talk | contribs)
m improved wording in binary cache section
Frontear (talk | contribs)
m add a small desc of host/build platform
Line 1: Line 1:
{{Expansion}}
{{Expansion}}
Cross compiling is well supported in [[Nixpkgs]] since 18.09<sup>[citation needed]</sup>.
[[Nixpkgs]] provides excellent support in configuring it for cross-platform compiling tasks since 18.09<sup>[citation needed]</sup>.
 
In order to prepare Nixpkgs for a cross-compiling environment, it needs to be aware of both the platform that performs the build-step, and the platform that will execute the resulting binaries. The former is referred to as the <code>buildPlatform</code>, while the latter is <code>hostPlatform</code>.<blockquote>If you were compiling a program from your system for a Raspberry PI, you would be the <code>buildPlatform</code> whereas the Raspberry PI would be the <code>hostPlatform</code>.</blockquote>Furthermore, in order to provide a more granular control to declaring dependencies in these environments, Nixpkgs derivations expose an exhaustive set of attributes that can explicitly define when are where dependencies are required. An exhaustive reference to these can be found in the [https://nixos.org/manual/nixpkgs/unstable/#ssec-stdenv-dependencies-propagated Nixpkgs manual].


== Getting Started ==
== Getting Started ==
There are two main entry points to configure a Nixpkgs instance for cross compilation. The simplest one is to leverage <code>pkgs.pkgsCross</code>:<syntaxhighlight lang="nix">
Nixpkgs exposes two configuration attributes that map internally to the expected behaviors of the build/host platforms as described above. These attributes can be set when importing Nixpkgs as a Nix expression:<syntaxhighlight lang="nix">
let
let
   pkgs = import <nixpkgs> {};
   pkgs = import <nixpkgs> {
in pkgs.pkgsCross.aarch64-multiplatform.hello
    localSystem = "x86_64-linux"; # buildPlatform
</syntaxhighlight>The above will provide a derivation result for the hello derivation that can run on an <code>aarch64</code> system. A slightly less simple, but "purer" (i.e. reproducible) snippet involves configuring Nixpkgs as you import it:<syntaxhighlight lang="nix">
    crossSystem = "aarch64-linux"; # hostPlatform
  };
in pkgs.hello
</syntaxhighlight>The above will provide a derivation result for the hello derivation that can run on an <code>aarch64-linux</code> system. This can sometimes be tedious especially for common <code>hostPlatform</code> targets. Fortunately, Nixpkgs exposes a <code>pkgsCross</code> attribute that provides pre-configured cross compiling targets. The snippet above converted to using <code>pkgsCross</code> can be shorted to:<syntaxhighlight lang="nix">
let
let
   pkgs = import <nixpkgs> {
   pkgs = import <nixpkgs> {
    # localSystem will always default to your current system, meaning it is not essential to define here.
     localSystem = "x86_64-linux";
    # It is however, encouraged if you are trying to follow nix's purity model.
 
     localSystem = "x86_64-linux"; # This should match the system you are compiling from (your running system)
    crossSystem = "aarch64-linux"; # This should match the system you are compiling for (your target system)
   };
   };
in pkgs.hello # The hello derivation will be built for aarch64-linux
in pkgs.pkgsCross.aarch64-multiplatform.hello
</syntaxhighlight>You can perform the same operations using the CLI, though you will probably prefer to use <code>pkgsCross</code> in that case, as its less verbose:<syntaxhighlight lang="bash">
</syntaxhighlight>You can perform the same operations using the CLI, and Nix will correctly evaluate the <code>localSystem</code> based on your current system:<syntaxhighlight lang="bash">
nix-build '<nixpkgs>' -A pkgsCross.aarch64-multiplatform.hello # nix-legacy
nix-build '<nixpkgs>' -A pkgsCross.aarch64-multiplatform.hello # nix-legacy
nix build nixpkgs#pkgsCross.aarch64-multiplatform.hello # nix3
nix build nixpkgs#pkgsCross.aarch64-multiplatform.hello # nix3
Line 23: Line 24:
$ nix-instantiate --eval --expr 'builtins.attrNames (import <nixpkgs> {}).pkgsCross' --json | nix-shell -p jq --command 'jq' # nix-legacy
$ nix-instantiate --eval --expr 'builtins.attrNames (import <nixpkgs> {}).pkgsCross' --json | nix-shell -p jq --command 'jq' # nix-legacy
$ nix eval --impure --expr 'builtins.attrNames (import <nixpkgs> {}).pkgsCross' --json | nix run nixpkgs#jq # nix3
$ nix eval --impure --expr 'builtins.attrNames (import <nixpkgs> {}).pkgsCross' --json | nix run nixpkgs#jq # nix3
</syntaxhighlight>If you instead prefer to write your systems directly, through <code>localSystem</code> and <code>crossSystem</code>, you can refer to [https://github.com/NixOS/nixpkgs/blob/master/lib/systems/examples.nix nixpkgs/lib/systems/examples.nix] for a list of platforms exposed as attributes (though it will be easier to use <code>pkgsCross</code> in this case). These can be directly used in-place for the aforementioned arguments:<syntaxhighlight lang="nix">
</syntaxhighlight>If you instead prefer to write your systems directly, through <code>localSystem</code> and <code>crossSystem</code>, you can refer to [https://github.com/NixOS/nixpkgs/blob/master/lib/systems/examples.nix nixpkgs/lib/systems/examples.nix] for examples of platforms exposed as attributes. These can be directly used in-place for the aforementioned arguments:<syntaxhighlight lang="nix">
let
let
   lib = import <nixpkgs/lib>;
   lib = import <nixpkgs/lib>;
Line 40: Line 41:
{
{
   pkgs ? import <nixpkgs> {
   pkgs ? import <nixpkgs> {
     # localSystem = "x86_64-linux"; # not necessary but encouraged
     localSystem = "x86_64-linux";
     crossSystem = "aarch64-linux";
     crossSystem = "aarch64-linux";
   },
   },
Line 86: Line 87:
</syntaxhighlight>The above snippet will drop you into a devshell that provides <code>pkg-config</code> as a native binary (accessible through <code>$PKG_CONFIG</code>), while also allowing linking to a valid <code>libGL</code> for the <code>crossSystem</code>.
</syntaxhighlight>The above snippet will drop you into a devshell that provides <code>pkg-config</code> as a native binary (accessible through <code>$PKG_CONFIG</code>), while also allowing linking to a valid <code>libGL</code> for the <code>crossSystem</code>.


For more information regarding the above, namely the usage of <code>nativeBuildInputs</code> and <code>buildInputs</code>, see [https://nixos.org/manual/nixpkgs/stable/#ssec-stdenv-dependencies stdenv dependencies] for a in-depth explanation. Alternatively, a simplified explanation can be found in a comment on the [https://github.com/NixOS/nixpkgs/pull/50881 nixpkgs repo].
For more information regarding the above, namely the usage of <code>nativeBuildInputs</code> and <code>buildInputs</code>, see [https://nixos.org/manual/nixpkgs/stable/#ssec-stdenv-dependencies stdenv dependencies] for a in-depth explanation. Alternatively, a simplified explanation can be found in a comment on the [https://github.com/NixOS/nixpkgs/pull/50881 Nixpkgs repo].


== Tips and tricks ==
== Tips and tricks ==