diff --git a/.github/workflows/riscv64-cross-ci.yml b/.github/workflows/riscv64-cross-ci.yml new file mode 100644 index 0000000..928521c --- /dev/null +++ b/.github/workflows/riscv64-cross-ci.yml @@ -0,0 +1,49 @@ +name: RISC-V 64bit cross-compiler CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Prepare git + run: + git config --global url."git://github.com/ghc/packages-".insteadOf git://github.com/ghc/packages/ && + git config --global url."http://github.com/ghc/packages-".insteadOf http://github.com/ghc/packages/ && + git config --global url."https://github.com/ghc/packages-".insteadOf https://github.com/ghc/packages/ && + git config --global url."ssh://git@github.com/ghc/packages-".insteadOf ssh://git@github.com/ghc/packages/ && + git config --global url."git@github.com:ghc/packages-".insteadOf git@github.com:ghc/packages/ + + - name: Checkout GHC + uses: actions/checkout@v2.4.0 + with: + repository: ghc/ghc + submodules: recursive + + - name: Checkout ghc.nix + uses: actions/checkout@v2.4.0 + with: + path: ghc.nix + + - name: Install nix + uses: cachix/install-nix-action@v20 + + - name: Use cachix + uses: cachix/cachix-action@v12 + with: + name: ghc-nix + signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}' + + - name: Run nix-shell - Boot and Configure + run: nix-shell --pure ghc.nix/shell.nix --arg withLlvm true --arg crossTarget '"riscv64"' --command "./boot && configure_ghc" + + - name: Run nix-shell - cabal update + run: nix-shell --pure ghc.nix/shell.nix --arg withLlvm true --arg crossTarget '"riscv64"' --command "pushd hadrian; cabal update; popd" + + - name: Run nix-shell - Build GHC + run: nix-shell --pure ghc.nix/shell.nix --arg withLlvm true --arg crossTarget '"riscv64"' --command "hadrian/build -j --flavour=quickest" diff --git a/README.md b/README.md index 36b922b..49cad7a 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,24 @@ It's trivial! $ nix-shell ~/ghc.nix/shell.nix --arg nixpkgs '(import {}).pkgsi686Linux' ``` +## Building a cross-compiler + +Cross-compiling in this section means: GHC is developed/built on one +architecture (`--build`) to run on the same architecture (`--host`) and target +another architecture (`--target`). + +E.g. develop GHC on *amd64*, run it on *amd64* and let the resulting GHC produce +binaries for *riscv64*. + +The `crossTarget` argument defines the target. The string must be a supported +architecture in `nixpkgs.pkgsCross`. When `crossTarget` is defined, all required +environment variables and `configure_ghc` parameters are setup for building a +cross-compiler. + +``` sh +nix-shell --pure ghc.nix/shell.nix --arg withLlvm true --arg crossTarget '"riscv64"' +``` + ## 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: diff --git a/ghc.nix b/ghc.nix index d26b44e..2850a47 100644 --- a/ghc.nix +++ b/ghc.nix @@ -28,6 +28,7 @@ in , withDtrace ? (pkgsFor nixpkgs system).stdenv.isLinux , withGrind ? !((pkgsFor nixpkgs system).valgrind.meta.broken or false) , withEMSDK ? false # load emscripten for js-backend +, crossTarget ? null # a `nixpkgs.pkgsCross` record, e.g. `riscv64` }: let @@ -58,15 +59,20 @@ let pkgs-unstable = import nixpkgs-unstable { inherit system; overlays = [ overlay ]; }; + + pkgs-cross = if crossTarget != null then pkgs.pkgsCross.${crossTarget} else null; in with pkgs; let llvmForGhc = + let + ps = if crossTarget == null then pkgs else pkgs-cross.buildPackages; + in if lib.versionAtLeast version "9.1" - then llvm_10 - else llvm_9; + then ps.llvm_12 + else ps.llvm_9; stdenv = if useClang @@ -176,23 +182,50 @@ hspkgs.shellFor rec { # 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-includes=${ncurses.dev}/include" - "--with-curses-libraries=${ncurses.out}/lib" - ] ++ lib.optionals withNuma [ - "--with-libnuma-includes=${numactl}/include" - "--with-libnuma-libraries=${numactl}/lib" - ] ++ lib.optionals withDwarf [ - "--with-libdw-includes=${elfutils.dev}/include" - "--with-libdw-libraries=${elfutils.out}/lib" - "--enable-dwarf-unwind" - ]; + + CONFIGURE_ARGS = + if crossTarget == null then + [ + "--with-gmp-includes=${gmp.dev}/include" + "--with-gmp-libraries=${gmp}/lib" + "--with-curses-includes=${ncurses.dev}/include" + "--with-curses-libraries=${ncurses.out}/lib" + ] ++ lib.optionals withNuma [ + "--with-libnuma-includes=${numactl}/include" + "--with-libnuma-libraries=${numactl}/lib" + ] ++ lib.optionals withDwarf [ + "--with-libdw-includes=${elfutils.dev}/include" + "--with-libdw-libraries=${elfutils.out}/lib" + "--enable-dwarf-unwind" + ] else [ + "--with-gmp-includes=${pkgs-cross.gmp.dev}/include" + "--with-gmp-libraries=${pkgs-cross.gmp}/lib" + "--with-curses-includes=${pkgs-cross.ncurses.dev}/include" + "--with-curses-libraries=${pkgs-cross.ncurses.out}/lib" + "--host=${stdenv.hostPlatform.config}" + "--target=${pkgs-cross.stdenv.hostPlatform.config}" + ]; + + + targetDependentShellHook = + if crossTarget == null then + '' + export CC=${stdenv.cc}/bin/cc + '' else + let + prefix = pkgs-cross.stdenv.cc.targetPrefix; + in + '' + # somehow, CC gets overridden so we set it again here. + export CC=${pkgs-cross.stdenv.cc}/bin/${prefix}cc + export CXX=${pkgs-cross.stdenv.cc}/bin/${prefix}c++ + export AR=${pkgs-cross.stdenv.cc.bintools.bintools}/bin/${prefix}ar + export RANLIB=${pkgs-cross.stdenv.cc.bintools.bintools}/bin/${prefix}ranlib + export NM=${pkgs-cross.stdenv.cc.bintools.bintools}/bin/${prefix}nm + export LD=${pkgs-cross.stdenv.cc.bintools}/bin/${prefix}ld + ''; shellHook = '' - # somehow, CC gets overridden so we set it again here. - export CC=${stdenv.cc}/bin/cc export GHC=$NIX_GHC export GHCPKG=$NIX_GHCPKG export HAPPY=${happy}/bin/happy @@ -216,8 +249,10 @@ hspkgs.shellFor rec { ${lib.optionalString withDocs "export FONTCONFIG_FILE=${fonts}"} + ${targetDependentShellHook} >&2 echo "Recommended ./configure arguments (found in \$CONFIGURE_ARGS:" - >&2 echo "or use the configure_ghc command):" + >&2 echo "or use the configure_ghc command - passing \$CONFIGURE_ARGS" + >&2 echo "itself to ./configure might not work):" >&2 echo "" >&2 echo " ${lib.concatStringsSep "\n " CONFIGURE_ARGS}" '';