Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wip/kiss cross #91

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,69 @@ It's trivial!
$ nix-shell ~/ghc.nix/ --arg nixpkgs '(import <nixpkgs> {}).pkgsi686Linux'
```

## Cross Compiling

This section describes how to build a cross-compiler, i.e. a compiler that runs
on one platform (like e.g. `amd64`) and produces code for another (e.g.
`aarch64`).

Currently this only works with a Makefile-based build. Hadrian uses the boot
GHC package manager to create the package database and old GHC package database
formats are incompatible to latest GHC versions.

### Create a cross-compiler Makefile

Put a file like this into `mk/build.mk`:

```Makefile
BuildFlavour = quick-cross
ifneq "$(BuildFlavour)" ""
include mk/flavours/$(BuildFlavour).mk
endif
Stage1Only = YES
HADDOCK_DOCS = NO
BUILD_SPHINX_HTML = NO
BUILD_SPHINX_PDF = NO
GhcLibHcOpts += -fPIC -keep-s-file
GhcRtsHcOpts += -fPIC
```

This will create a LLVM-based backend. It's crucial that the build is stopped
at `stage1` (`Stage1Only = YES`), because later stages are built with
previously compiled GHCs, that would create binaries for the target platform...

### Enter a cross-compiling nix enviroment

I prefer to use a `shell.nix` file to avoid long command lines. Put a
`shell.nix` into the GHC root directory:

```nix
import ghc.nix/default.nix {
version = "9.1";
withDocs = false;
withHadrianDeps = true;
crossTargetArch = "aarch64-unknown-linux-gnu";
nixCrossTools = "aarch64-multiplatform";
withLlvm = true;
withDwarf = false;
}
```

`crossTargetArch` is the arch identifier; processor, operating system, ABI,
etc. It's the target of the GHC to built. `nixCrossTools` defines which tools
to use from `nixpkgs.pkgsCross`.

You can enter the enviroment by simply calling `nix-shell`.

### Boot, configure and make

```bash
./boot && configure_ghc
make -j
```

`configure_ghc` sets up the paths to all required libraries.

## Cachix

There is a Cachix cache ([ghc-nix](https://app.cachix.org/cache/ghc-nix)) which is filled by our CI. To use it, run the following command and follow the instructions:
Expand Down
60 changes: 52 additions & 8 deletions default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ in
, withNuma ? nixpkgs.stdenv.isLinux
, withDtrace ? nixpkgs.stdenv.isLinux
, withGrind ? true
, crossTargetArch ? null # E.g. "aarch64-unknown-linux-gnu"
, nixCrossTools ? null # E.g. "aarch64-multiplatform"
}:

with nixpkgs;
Expand Down Expand Up @@ -53,6 +55,8 @@ let
fonts = nixpkgs.makeFontsConf { fontDirectories = [ nixpkgs.dejavu_fonts ]; };
docsPackages = if withDocs then [ python3Packages.sphinx ourtexlive ] else [];

isCross = assert (nixCrossTools == null) == (crossTargetArch == null); nixCrossTools != null;

depsSystem = with stdenv.lib; (
[ autoconf automake m4 less
gmp.dev gmp.out glibcLocales
Expand All @@ -71,6 +75,26 @@ let
++ optional withGhcid ghcid
++ optionals withIde [ghcide]
++ optional withDtrace linuxPackages.systemtap
++ optionals isCross [
# cross toolchain
pkgsCross.${nixCrossTools}.buildPackages.binutils
pkgsCross.${nixCrossTools}.stdenv.cc

# cross libs
linuxHeaders
elf-header
pkgsCross.${nixCrossTools}.gmp.dev
pkgsCross.${nixCrossTools}.gmp.out
pkgsCross.${nixCrossTools}.ncurses.dev
pkgsCross.${nixCrossTools}.ncurses.out
(optionalString withNuma pkgsCross.${nixCrossTools}.numactl)

# TODO: Add withDwarf dependencies here.
# The elfutils package currently doesn't cross-compile.

# to execute cross-compiled programms.
qemu
]
++ (if (! stdenv.isDarwin)
then [ pxz ]
else [
Expand Down Expand Up @@ -104,6 +128,10 @@ let
];
librarySystemDepends = depsSystem;
});
pkgsSource = if !isCross then
nixpkgs
else
pkgsCross.${nixCrossTools};
in
(hspkgs.shellFor rec {
packages = pkgset: [ hsdrv ];
Expand All @@ -115,21 +143,36 @@ in
# In particular, this makes many tests fail because those warnings show up in test outputs too...
# The solution is from: https://github.com/NixOS/nix/issues/318#issuecomment-52986702
LOCALE_ARCHIVE = if stdenv.isLinux then "${glibcLocales}/lib/locale/locale-archive" else "";
CONFIGURE_ARGS = [ "--with-gmp-includes=${gmp.dev}/include"
"--with-gmp-libraries=${gmp}/lib"
"--with-curses-libraries=${ncurses.out}/lib"
CONFIGURE_ARGS = [ "--with-gmp-includes=${pkgsSource.gmp.dev}/include"
"--with-gmp-libraries=${pkgsSource.gmp}/lib"
"--with-curses-libraries=${pkgsSource.ncurses.out}/lib"
] ++ lib.optionals withNuma [
"--with-libnuma-includes=${numactl}/include"
"--with-libnuma-libraries=${numactl}/lib"
"--with-libnuma-includes=${pkgsSource.numactl}/include"
"--with-libnuma-libraries=${pkgsSource.numactl}/lib"
] ++ lib.optionals withDwarf [
"--with-libdw-includes=${elfutils}/include"
"--with-libdw-libraries=${elfutils}/lib"
"--with-libdw-includes=${pkgsSource.elfutils}/include"
"--with-libdw-libraries=${pkgsSource.elfutils}/lib"
"--enable-dwarf-unwind"
] ++ lib.optionals isCross [
"--target=${crossTargetArch}"
"--enable-bootstrap-with-devel-snapshot"
];

TARGET_DEPS_EXPORTS = if !isCross then
"export CC=${stdenv.cc}/bin/cc"
else
''
export NM=${crossTargetArch}-nm
export LD=${crossTargetArch}-ld.gold
export AR=${crossTargetArch}-ar
export AS=${crossTargetArch}-as
export CC=${crossTargetArch}-cc
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not work for MIPS64, namely mips64el-unknown-linux-gnu

export CXX=${crossTargetArch}-cxx
'';

shellHook = let toYesNo = b: if b then "YES" else "NO"; in ''
# somehow, CC gets overriden so we set it again here.
export CC=${stdenv.cc}/bin/cc
${TARGET_DEPS_EXPORTS}
export HAPPY=${happy}/bin/happy
export ALEX=${hspkgs.alex}/bin/alex
${lib.optionalString withLlvm "export LLC=${llvmForGhc}/bin/llc"}
Expand All @@ -147,6 +190,7 @@ in

validate_ghc() { config_args="$CONFIGURE_ARGS" ./validate $@; }

${lib.optionalString isCross "echo 'Please make sure you only build up to Stage1 (see UserSettings.hs in hadrian).'"}
>&2 echo "Recommended ./configure arguments (found in \$CONFIGURE_ARGS:"
>&2 echo "or use the configure_ghc command):"
>&2 echo ""
Expand Down