Cross compiling: Difference between revisions
Phanirithvij (talk | contribs) m add another way via nix-build cli to cross compile |
m Roxwize moved page Cross Compiling to Cross compiling: sentence case |
||
| (3 intermediate revisions by 2 users not shown) | |||
| Line 5: | Line 5: | ||
== Getting Started == | == Getting Started == | ||
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"> | 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 | ||
| Line 18: | Line 19: | ||
}; | }; | ||
in pkgs.pkgsCross.aarch64-multiplatform.hello | in pkgs.pkgsCross.aarch64-multiplatform.hello | ||
</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= | </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=console> | ||
nix-build '<nixpkgs>' -A pkgsCross.aarch64-multiplatform.hello # nix-legacy | $ nix-build '<nixpkgs>' -A pkgsCross.aarch64-multiplatform.hello # nix-legacy | ||
nix-build '<nixpkgs>' --arg crossSystem '(import <nixpkgs> {}).lib.systems.examples.aarch64-multiplatform' -A hello # alternative way | $ nix-build '<nixpkgs>' --arg crossSystem '(import <nixpkgs> {}).lib.systems.examples.aarch64-multiplatform' -A hello # alternative way | ||
nix build nixpkgs#pkgsCross.aarch64-multiplatform.hello # nix3 | $ nix build nixpkgs#pkgsCross.aarch64-multiplatform.hello # nix3 | ||
</syntaxhighlight>All of the above snippets will resolve to the exact same derivation result, which will provide a binary for GNU Hello that can execute only on an <code>aarch64</code> system. There are many other systems <code>pkgsCross</code> has defined, you can see an exhaustive list of all of them on your system:<syntaxhighlight lang= | </syntaxhighlight>All of the above snippets will resolve to the exact same derivation result, which will provide a binary for GNU Hello that can execute only on an <code>aarch64</code> system. There are many other systems <code>pkgsCross</code> has defined, you can see an exhaustive list of all of them on your system:<syntaxhighlight lang=console> | ||
$ 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 | ||
| Line 39: | Line 40: | ||
=== Basics === | === Basics === | ||
Using the same ideas as above, we can create development environments which provide us with a compilation suite that can perform cross-compilation for us. A very simple [[Development environment with nix-shell|development shell]] (colloquially called a "devshell") can be written as: | Using the same ideas as above, we can create development environments which provide us with a compilation suite that can perform cross-compilation for us. A very simple [[Development environment with nix-shell|development shell]] (colloquially called a "devshell") can be written as: | ||
{{file|shell.nix|nix|3= | |||
{ | { | ||
pkgs ? import <nixpkgs> { | pkgs ? import <nixpkgs> { | ||
| Line 56: | Line 57: | ||
} | } | ||
) { } | ) { } | ||
}} | |||
Entering this development shell via <code>nix-shell shell.nix</code> will add the relevant compiler tools to your PATH temporarily. Similar to other Linux systems, all cross-compiling tools are prefixed with relevant platform prefixes, which means simply typing <code>gcc</code> will not work. However, the provided <code>mkShell</code> will introduce environment variables for your devshell, such as <code>$CC</code>, <code>$AR</code>, <code>$LD</code>, and more. At the time of writing, official documentation on an exhaustive list of these variables does not exist, but you can view them for your devshell through the command-line: | |||
<syntaxhighlight lang=console> | |||
$ $EDITOR $(nix-build ./shell.nix) # opens your EDITOR with a massive bash script full of declare -x ... | $ $EDITOR $(nix-build ./shell.nix) # opens your EDITOR with a massive bash script full of declare -x ... | ||
</syntaxhighlight>Given these environment variables, you can run compile your software using the exact same commands with fairly minimal changes (changing hardcoded <code>gcc</code> values into $CC, for example):<syntaxhighlight lang= | </syntaxhighlight> | ||
Given these environment variables, you can run compile your software using the exact same commands with fairly minimal changes (changing hardcoded <code>gcc</code> values into $CC, for example): | |||
<syntaxhighlight lang=console> | |||
$ $CC -o main src/main.c | $ $CC -o main src/main.c | ||
$ file main | $ file main | ||
main: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /nix/store/qa51m8r8rjnigk5hf7sxv0hw7qr7l4bc-glibc-aarch64-unknown-linux-gnu-2.39-52/lib/ld-linux-aarch64.so.1, for GNU/Linux 3.10.0, not stripped | main: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /nix/store/qa51m8r8rjnigk5hf7sxv0hw7qr7l4bc-glibc-aarch64-unknown-linux-gnu-2.39-52/lib/ld-linux-aarch64.so.1, for GNU/Linux 3.10.0, not stripped | ||
</syntaxhighlight>The above snippet will have minor differences depending on when you run it, but the main thing to notice is <code>ARM aarch64</code>, which tells us our software was able to successfully cross compile. | </syntaxhighlight> | ||
The above snippet will have minor differences depending on when you run it, but the main thing to notice is <code>ARM aarch64</code>, which tells us our software was able to successfully cross compile. | |||
=== Declaring dependencies === | === Declaring dependencies === | ||
If you try to declare build-time dependencies within the devshell (such as <code>pkgs.cmake</code>), you will quickly realize that these derivations are actually being built for the <code>crossSystem</code>, making them unusable on your system architecture (see [https://github.com/NixOS/nixpkgs/issues/49526 #49526]). There are ways around this, but in general once you've gotten to this point you should prefer [https://nixos.org/manual/nixpkgs/unstable/#chap-stdenv writing a derivation], which will make it not only easier to write both derivations, but will allow you to follow the recommended practices for using Nix. | If you try to declare build-time dependencies within the devshell (such as <code>pkgs.cmake</code>), you will quickly realize that these derivations are actually being built for the <code>crossSystem</code>, making them unusable on your system architecture (see [https://github.com/NixOS/nixpkgs/issues/49526 #49526]). There are ways around this, but in general once you've gotten to this point you should prefer [https://nixos.org/manual/nixpkgs/unstable/#chap-stdenv writing a derivation], which will make it not only easier to write both derivations, but will allow you to follow the recommended practices for using Nix. | ||
| Line 104: | Line 111: | ||
=== Executing cross compiled binaries === | === Executing cross compiled binaries === | ||
By using [[QEMU]], we can natively execute a cross-compiled binary through an emulation layer. This will result in degraded performance but is very suitable for testing the functionality of a binary. | By using [[QEMU]], we can natively execute a cross-compiled binary through an emulation layer. This will result in degraded performance but is very suitable for testing the functionality of a binary. | ||
If you are on NixOS, this functionality can be provided automatically on any cross-compiled binary by setting [https://nixos.org/manual/nixos/unstable/options#opt-boot.binfmt.emulatedSystems boot.binfmt.emulatedSystems] in your configuration. After rebuilding, attempting to run a cross-compiled binary will automatically invoke <code>qemu</code> indirectly through the [https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html binfmt_misc kernel feature].<syntaxhighlight lang=" | If you are on NixOS, this functionality can be provided automatically on any cross-compiled binary by setting [https://nixos.org/manual/nixos/unstable/options#opt-boot.binfmt.emulatedSystems boot.binfmt.emulatedSystems] in your configuration. After rebuilding, attempting to run a cross-compiled binary will automatically invoke <code>qemu</code> indirectly through the [https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html binfmt_misc kernel feature]. | ||
<syntaxhighlight lang="console"> | |||
$ ./result | $ ./result | ||
Hello World! | Hello World! | ||
$ ./result-aarch64-linux | $ ./result-aarch64-linux | ||
Hello World! | Hello World! | ||
</syntaxhighlight>Otherwise, you can use the <code>pkgs.qemu-user</code> to download qemu user space programs (or use any installed by your distro) to run your package easily.<syntaxhighlight lang=" | </syntaxhighlight> | ||
Otherwise, you can use the <code>pkgs.qemu-user</code> to download qemu user space programs (or use any installed by your distro) to run your package easily. | |||
<syntaxhighlight lang="console"> | |||
$ ./result | $ ./result | ||
Hello World! | Hello World! | ||
| Line 119: | Line 130: | ||
=== Leveraging the binary cache === | === Leveraging the binary cache === | ||
You will likely have noticed that resolving derivations through either pkgsCross or a configured Nixpkgs instance results in your system needing to build the binary. This is because cross-compiled binaries are not cached on the official [[Binary Cache|binary cache]]. Fortunately, there are a small set of systems that are actively built and cached officially. At the time of writing, this only includes <code>aarch64-linux</code>, <code>aarch64-darwin</code>, <code>i686-linux</code>, <code>x86_64-linux</code>, and <code>x86_64-darwin</code>. If your platform targets include these, you may be able to leverage a slight hack to avoid large-scale builds.<blockquote>Please note that this is not recommended, as it hacks around some internal details of Nixpkgs which are subject to change at any time, and the storage requirements will be higher due to duplicate(but different system) packages.</blockquote>An example of this using <code>pkgs.SDL2</code>:<syntaxhighlight lang="nix"> | You will likely have noticed that resolving derivations through either pkgsCross or a configured Nixpkgs instance results in your system needing to build the binary. This is because cross-compiled binaries are not cached on the official [[Binary Cache|binary cache]]. Fortunately, there are a small set of systems that are actively built and cached officially. At the time of writing, this only includes <code>aarch64-linux</code>, <code>aarch64-darwin</code>, <code>i686-linux</code>, <code>x86_64-linux</code>, and <code>x86_64-darwin</code>. If your platform targets include these, you may be able to leverage a slight hack to avoid large-scale builds.<blockquote>Please note that this is not recommended, as it hacks around some internal details of Nixpkgs which are subject to change at any time, and the storage requirements will be higher due to duplicate(but different system) packages.</blockquote>An example of this using <code>pkgs.SDL2</code>:<syntaxhighlight lang="nix"> | ||
let | let | ||
| Line 194: | Line 206: | ||
* [https://logs.nix.samueldr.com/nixos/2018-08-03#1533327247-1533327971; 2018-08-03 discussion on #nixos] ([https://matrix.to/#/!AinLFXQRxTuqNpXyXk:matrix.org/$15333274371713496LOAor:matrix.org Mirror of chat on Matrix.org]) | * [https://logs.nix.samueldr.com/nixos/2018-08-03#1533327247-1533327971; 2018-08-03 discussion on #nixos] ([https://matrix.to/#/!AinLFXQRxTuqNpXyXk:matrix.org/$15333274371713496LOAor:matrix.org Mirror of chat on Matrix.org]) | ||
* [https://nixcademy.com/posts/cpp-with-nix-in-2023-part-2-package/ C++ with Nix in 2023, Part 2: Package Generation and Cross-Compilation, Nixcademy] | |||
* [https://nixcademy.com/posts/cross-compilation-with-nix/ Separation of Concerns in Cross-Compilation, Nixcademy] | |||
* [https://nixcademy.com/posts/cross-compile-nixos-images/ Cross-Compiling NixOS images, Nixcademy] | |||
[[Category:nix]] | [[Category:nix]] | ||
[[Category:Development]] | [[Category:Development]] | ||