1
0
Fork 0
mirror of https://github.com/NixOS/nix.dev.git synced 2024-10-18 14:32:43 -04:00
nix.dev/source/tutorials/cross-compilation.rst

263 lines
9.3 KiB
ReStructuredText
Raw Normal View History

2021-06-14 12:54:27 -04:00
.. _ref-cross-compilation:
Cross-compilation
=================
Cross-compilation is the act of **compiling code** on the **build platform**
to the **host platform**, where the compiled **executable runs**. [#]_
It's needed when the host platform has limited resources (such as CPU)
or when it's not easily accessible for development.
2021-06-15 06:15:16 -04:00
The Nix community has world-class support for cross-compilation,
2021-06-14 12:54:27 -04:00
after years of hard work from our community.
2021-06-15 09:41:39 -04:00
.. [#] Terminology for cross-compilation platforms differs between build systems.
We have chosen to follow
2021-06-14 12:54:27 -04:00
`autoconf terminology <https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Hosts-and-Cross_002dCompilation.html>`_.
2021-06-15 09:41:39 -04:00
.. note:: macOS/Darwin is a special case, as not the whole OS is open-source.
2021-06-14 12:54:27 -04:00
It's only possible to cross-compile between ``aarch64-darwin`` and ``x86_64-darwin``.
What's a target platform?
-------------------------
2021-06-15 09:41:39 -04:00
There's actually a third platform named the target platform.
2021-06-14 12:54:27 -04:00
It matters in cases where you'd like to distribute a compiler binary,
as you'd then like to build a compiler on the build platform, compile code on the
2021-06-15 06:15:16 -04:00
host plaform and run the final executable on the target platform.
2021-06-14 12:54:27 -04:00
2021-06-15 09:41:39 -04:00
Since that's rarely needed, we'll treat the target platform the same as the host.
2021-06-14 12:54:27 -04:00
2021-06-15 06:15:16 -04:00
Determining the host platform config
------------------------------------
2021-06-14 12:54:27 -04:00
The build platform is determined automatically by Nix
as it can just guess it during the configure phase.
The host platform is best determined by running on the host platform:
.. code:: shell-session
$ bash $(nix-build '<nixpkgs>' -A gnu-config)/config.guess
aarch64-unknown-linux-gnu
In case that's not possible (when the host platform is not easily accessible
2021-06-15 09:41:39 -04:00
for development), the platform config has to be constructed manually via the following template:
2021-06-14 12:54:27 -04:00
.. code::
<cpu>-<vendor>-<os>-<abi>
Note that ``<vendor>`` is often ``unknown`` and ``<abi>`` is optional.
There's also no unique identifier for a platform, for example ``unknown`` and
``pc`` are interchangeable (hence it's called config.guess).
2021-06-15 06:15:16 -04:00
If you can't install Nix, find a way to run ``config.guess`` (usually comes with
the autoconf package) from the OS you're able to run on the host platform.
2021-06-15 06:15:16 -04:00
Some other common examples of platform configs:
2021-06-14 12:54:27 -04:00
- aarch64-apple-darwin14
- aarch64-pc-linux-gnu
- x86_64-w64-mingw32
- aarch64-apple-ios
Choosing the host platform with Nix
-----------------------------------
2021-06-15 09:41:39 -04:00
Nixpkgs comes with a set of predefined host platforms applied to all packages.
2021-06-14 12:54:27 -04:00
2021-06-15 06:15:16 -04:00
It's possible to list predefined attribute sets via shell completion:
2021-06-14 12:54:27 -04:00
.. code:: shell-session
$ nix-build '<nixpkgs>' -A pkgsCross.<TAB>
pkgsCross.aarch64-android pkgsCross.musl32
pkgsCross.aarch64-android-prebuilt pkgsCross.musl64
pkgsCross.aarch64be-embedded pkgsCross.muslpi
pkgsCross.aarch64-darwin pkgsCross.musl-power
pkgsCross.aarch64-embedded pkgsCross.or1k
pkgsCross.aarch64-multiplatform pkgsCross.pogoplug4
pkgsCross.aarch64-multiplatform-musl pkgsCross.powernv
pkgsCross.amd64-netbsd pkgsCross.ppc64
pkgsCross.arm-embedded pkgsCross.ppc64-musl
pkgsCross.armhf-embedded pkgsCross.ppc-embedded
pkgsCross.armv7a-android-prebuilt pkgsCross.ppcle-embedded
pkgsCross.armv7l-hf-multiplatform pkgsCross.raspberryPi
pkgsCross.avr pkgsCross.remarkable1
pkgsCross.ben-nanonote pkgsCross.remarkable2
pkgsCross.fuloongminipc pkgsCross.riscv32
pkgsCross.ghcjs pkgsCross.riscv32-embedded
pkgsCross.gnu32 pkgsCross.riscv64
pkgsCross.gnu64 pkgsCross.riscv64-embedded
pkgsCross.i686-embedded pkgsCross.scaleway-c1
pkgsCross.iphone32 pkgsCross.sheevaplug
pkgsCross.iphone32-simulator pkgsCross.vc4
pkgsCross.iphone64 pkgsCross.wasi32
pkgsCross.iphone64-simulator pkgsCross.x86_64-embedded
pkgsCross.mingw32 pkgsCross.x86_64-netbsd
pkgsCross.mingwW64 pkgsCross.x86_64-netbsd-llvm
pkgsCross.mmix pkgsCross.x86_64-unknown-redox
pkgsCross.msp430
Cross-compilation package attribute names are made up, so it isn't always clear
what is the corresponding platform config.
2021-06-14 12:54:27 -04:00
2021-06-15 09:41:39 -04:00
It's possible to query the platform config using:
2021-06-14 12:54:27 -04:00
$ nix-instantiate '<nixpkgs>' -A pkgsCross.aarch64-darwin.hostPlatform.config --eval
"aarch64-apple-darwin"
2021-06-15 06:15:16 -04:00
.. note:: In case the plaform you seek hasn't been defined yet, feel free to contribute one
2021-06-14 12:54:27 -04:00
by `adding it upstream <https://github.com/NixOS/nixpkgs/blob/master/lib/systems/examples.nix>`_.
Cross-compiling for the first time!
-----------------------------------
To cross-compile a package like `hello <https://www.gnu.org/software/hello/>`_,
2021-06-15 09:41:39 -04:00
pick the platform attribute - ``aarch64-multiplatform`` in our case - and run:
2021-06-14 12:54:27 -04:00
.. code:: shell-session
$ nix-build '<nixpkgs>' -A pkgsCross.aarch64-multiplatform.hello
...
/nix/store/pzi2h0d60nb4ydcl3nn7cbxxdnibw3sy-hello-aarch64-unknown-linux-gnu-2.10
`Search for a package <https://search.nixos.org/packages>`_ attribute name to find the
2021-06-15 09:41:39 -04:00
one that you're interested in building.
2021-06-14 12:54:27 -04:00
2021-06-15 09:41:39 -04:00
Real-world cross-compiling of a Hello World example
2021-06-14 12:54:27 -04:00
---------------------------------------------------
To show off the power of cross-compilation in Nix, let's build our own Hello World program
by cross-compiling it as static executables to ``armv6l-unknown-linux-gnueabihf``
and ``x86_64-w64-mingw32`` (Windows) platforms and run the resulting executable
with `an emulator <https://en.wikipedia.org/wiki/Emulator>`_.
.. code:: nix
{ pkgs ? import <nixpkgs> {}
}:
let
# Create a C program that prints Hello World
helloWorld = pkgs.writeText "hello.c" ''
#include <stdio.h>
int main (void)
{
printf ("Hello, world!\n");
return 0;
}
'';
# A function that takes host platform packages
crossCompileFor = hostPkgs:
# Run a simple command with the compiler available
hostPkgs.runCommandCC "hello-world-cross-test" {} ''
# Wine requires home directory
HOME=$PWD
# Compile our example using the compiler specific to our host platform
$CC ${helloWorld} -o hello
2021-06-15 06:15:16 -04:00
# Run the compiled program using user mode emulation (Qemu/Wine)
2021-06-15 09:41:39 -04:00
# buildPackages is passed so that emulation is built for the build platform
2021-06-14 12:54:27 -04:00
${hostPkgs.stdenv.hostPlatform.emulator hostPkgs.buildPackages} hello > $out
2021-06-15 09:41:39 -04:00
# print to stdout
2021-06-14 12:54:27 -04:00
cat $out
'';
in {
# Statically compile our example using the two platform hosts
rpi = crossCompileFor pkgs.pkgsCross.raspberryPi;
windows = crossCompileFor pkgs.pkgsCross.mingwW64;
}
If we build this example and print both resulting derivations, we should see "Hello, world!" for each:
.. code:: shell-session
$ cat $(nix-build cross-compile.nix)
Hello, world!
Hello, world!
Developer environment with a cross-compiler
-------------------------------------------
2021-06-15 09:41:39 -04:00
In the :ref:`tutorial for declarative reproducible environments <declarative-reproducible-envs>`,
we looked at how Nix helps us provide tooling and system libraries for our project.
2021-06-14 12:54:27 -04:00
2021-06-15 09:41:39 -04:00
It's also possible to provide an environment with a compiler configured for cross-compilation.
2021-06-14 12:54:27 -04:00
Given we have a ``shell.nix``:
.. code:: nix
{ nixpkgs ? fetchTarball "https://github.com/NixOS/nixpkgs/archive/bba3474a5798b5a3a87e10102d1a55f19ec3fca5.tar.gz"
, pkgs ? (import nixpkgs {}).pkgsCross.aarch64-multiplatform
}:
# pkgs.callPackage is needed due to https://github.com/NixOS/nixpkgs/pull/126844
2021-06-15 06:15:16 -04:00
pkgs.callPackage ({ mkShell, zlib, pkg-config, file }: mkShell {
2021-06-15 09:41:39 -04:00
# these tools run on the build platform, but are configured to target the target platform
2021-06-14 12:54:27 -04:00
nativeBuildInputs = [ pkg-config file ];
# libraries needed for the target platform
buildInputs = [ zlib ];
}) {}
And ``hello.c``:
.. code:: c
#include <stdio.h>
int main (void)
{
printf ("Hello, world!\n");
return 0;
}
We can cross-compile it:
.. code:: shell-session
$ nix-shell --run '$CC hello.c -o hello' cross-compile-shell.nix
And confirm it's aarch64:
.. code:: shell-session
$ nix-shell --run 'file hello' cross-compile-shell.nix
hello: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /nix/store/733hzlw1hixdm6dfdsb8dlwa2h8fl5qi-glibc-2.31-74-aarch64-unknown-linux-gnu/lib/ld-linux-aarch64.so.1, for GNU/Linux 2.6.32, with debug_info, not stripped
Next steps
----------
2021-06-15 09:41:39 -04:00
- The `official binary cache <https://cache.nixos.org>`_ doesn't come with binaries
2021-06-14 12:54:27 -04:00
for packages that are cross-compiled, so it's important to set up
:ref:`a binary cache and CI (GitHub Actions and Cachix) <github-actions>`.
- While many compilers in nixpkgs support cross-compilation,
not all of them do.
On top of that, supporting cross-compilation is not trivial
work and due to many possible combinations of what would
2021-06-15 09:41:39 -04:00
need to be tested, some packages might not build.
2021-06-14 12:54:27 -04:00
2021-06-15 09:41:39 -04:00
`A detailed explanation how of cross-compilation is implemented in Nix <https://nixos.org/manual/nixpkgs/stable/#chap-cross>`_ can help with fixing those issues.
2021-06-14 12:54:27 -04:00
2021-06-15 06:15:16 -04:00
- The Nix community has a `dedicated Matrix room <https://matrix.to/#/#cross-compiling:nixos.org>`_
2021-06-14 12:54:27 -04:00
for help around cross-compiling.