-
-
Notifications
You must be signed in to change notification settings - Fork 266
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
dedcd7b
commit 365c398
Showing
4 changed files
with
261 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,257 @@ | ||
.. _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. | ||
|
||
Nix community has world-class support for cross-compilation, | ||
after years of hard work from our community. | ||
|
||
.. [#] Terminology for cross-compilation platforms differs between build systems, | ||
Nix community has chosen to follow | ||
`autoconf terminology <https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Hosts-and-Cross_002dCompilation.html>`_. | ||
.. note:: macOS/Darwin is a special case, as not the whole OS is Open Source. | ||
It's only possible to cross-compile between ``aarch64-darwin`` and ``x86_64-darwin``. | ||
|
||
|
||
What's a target platform? | ||
------------------------- | ||
|
||
There's actually a third platform named target. | ||
|
||
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 | ||
target plaform and run the final executable on the host platform. | ||
|
||
Since that's rarely needed, we'll treat target platform the same as the build. | ||
|
||
|
||
Determining the host platform | ||
----------------------------- | ||
|
||
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 | ||
for development), it has to be constructed manually via the following template: | ||
|
||
.. 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). | ||
|
||
Some other common examples of platforms: | ||
|
||
- aarch64-apple-darwin14 | ||
- aarch64-pc-linux-gnu | ||
- x86_64-w64-mingw32 | ||
- aarch64-apple-ios | ||
|
||
|
||
Choosing the host platform with Nix | ||
----------------------------------- | ||
|
||
Nixpkgs comes with a set of predefined host plaform applied to all packages. | ||
|
||
It's possible to list predefined sets via shell completion: | ||
|
||
.. 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 | ||
From the attribute name it can't always be immediately clear what is the platform. | ||
|
||
It's possible to query the platform name using:: | ||
|
||
$ nix-instantiate '<nixpkgs>' -A pkgsCross.aarch64-darwin.hostPlatform.config --eval | ||
"aarch64-apple-darwin" | ||
|
||
.. note:: In case the plaforms hasn't been defined yet, feel free to contribute one | ||
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/>`_, | ||
pick the platform target name like ``aarch64-multiplatform`` in our case and run: | ||
|
||
.. 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 | ||
one that you're interested in to build. | ||
|
||
|
||
Real world cross-compiling of a Hello World example | ||
--------------------------------------------------- | ||
|
||
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 | ||
# Run the compiled program using an emulator | ||
# Usually Qemu, but on windows it is Wine | ||
${hostPkgs.stdenv.hostPlatform.emulator hostPkgs.buildPackages} hello > $out | ||
# print to stdout program stdout | ||
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 | ||
------------------------------------------- | ||
|
||
In :ref:`tutorial for declarative reproducible environments <declarative-reproducible-envs>`, | ||
we've looked at how Nix helps us provide tooling and system libraries for our project. | ||
|
||
It's also possible to provide an environment with a compiler configured for cross-compilation! | ||
|
||
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 | ||
pkgs.callPackage ({ mkShell, zlib, pkg-config }: mkShell { | ||
# these tools run on the build platform, but are configure to target the target platform | ||
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 | ||
---------- | ||
|
||
- `Official binary cache <https://cache.nixos.org>`_ doesn't come with binaries | ||
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 | ||
need to be tested, packages some might not build. | ||
|
||
`A detailed explanation how cross-compilation is implemented in Nix can help fixing those issues <https://nixos.org/manual/nixpkgs/stable/#chap-cross>`_. | ||
|
||
- Nix community has a `dedicated Matrix room <https://matrix.to/#/#cross-compiling:nixos.org>`_ | ||
for help around cross-compiling. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters