Commit cbc2f63d authored by Zhen Zhang's avatar Zhen Zhang Committed by Andrey Mokhov

Add cross compilation (#401)

Tested with arm-linux-gnueabihf.
parent 0781e16f
## Build a cross-compiling GHC
Our host machine is "Ubuntu 16.04.2 LTS, Linux ubuntu 4.4.0-79-generic 86_64".
We need to download necessary tools, including:
- [LLVM-4.0 source](http://releases.llvm.org/4.0.0/llvm-4.0.0.src.tar.xz), you need to build it yourself. Remember to choose release channel and use gold linker (`cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_USE_LINKER=gold ..`)
- `sudo apt-get install gcc-arm-linux-gnueabihf` to install the GCC cross-compiler
- Download and install [Haskell Platform 8.0.2](https://haskell.org/platform/download/8.0.2/haskell-platform-8.0.2-unknown-posix--full-x86_64.tar.gz). Install it according to [instructions here](https://www.haskell.org/platform/linux.html#linux-generic)
After all the dependencies are in place:
- `git clone https://github.com/ghc/ghc`
- `cd ghc`
- `git clone https://github.com/snowleopard/hadrian`
- `git submodule update --init`
- `./configure --target=arm-linux-gnueabihf`
- `cd hadrian`
- Modify `src/Settings.hs`, set `stage1Only` and `crossCompiling` to `True`.
- Build the compiler by e.g. `./build.cabal.sh --flavour=quickest --integer-simple --skip-configure -V -j`
After that, you should have built `inplace/bin/ghc-stage1` cross compiler. We will go to the next section to validate this.
## Test run
Write a simple hello world haskell program:
```haskell
module Main where
main = putStrLn "Hello, world!"
```
Compile it with cross-compiling GHC: `<ghc-folder>/inplace/bin/ghc-stage1 -static Main`. Note that we created a static version of it which packs together all depending libraries.
- Install QEMU: `sudo apt-get install qemu-system-arm`
- Download `vmlinuz` (kernel) and `initrd.gz` (initial ramdisk) from mirror like https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/dists/xenial/main/installer-armhf/current/images/generic-lpae/cdrom/.
- Add the ARM Linux executable `Main` to the initial ramdisk so we can load it directly into memory. No need for real installation
+ `gunzip initrd.gz` to get `initrd`
+ `mkdir tmp2; cd tmp2; sudo cpio -id < ../initrd` to get a file system
+ `cp /PATH/TO/Main usr/bin`
+ `find . | cpio --create --format='newc' > /tmp/newinitrd` to pack back the `initrd`
+ `gzip /tmp/newinitrd`
+ Move `newinitrd` to where `vmlinuz` is, rename it to `newinitrd.img`
+ Run the following configured QEMU:
```bash
#!/bin/sh
qemu-system-arm \
-kernel vmlinuz \
-initrd newinitrd.img \
-append "root=/dev/vda2 rootfstype=ext4" \
-no-reboot \
-nographic \
-m 1024 \
-M virt
```
This will lead you to a installer interface. But we don't need to do that, so we can save ourself from the hassel of setup networks etc. We just keep `Go Back`, until see a line `Execute a shell`, and select it. Now you get a shell, go find `/usr/bin/Main` and run it!
......@@ -89,8 +89,10 @@ executable hadrian
, Settings.Packages.Ghc
, Settings.Packages.GhcCabal
, Settings.Packages.Ghci
, Settings.Packages.GhcPkg
, Settings.Packages.GhcPrim
, Settings.Packages.Haddock
, Settings.Packages.Haskeline
, Settings.Packages.IntegerGmp
, Settings.Packages.Rts
, Settings.Packages.RunGhc
......
module Oracles.Flag (
Flag (..), flag, crossCompiling, platformSupportsSharedLibs,
Flag (..), flag, platformSupportsSharedLibs,
ghcWithSMP, ghcWithNativeCodeGen, supportsSplitObjects
) where
......@@ -43,9 +43,6 @@ flag f = do
++ quote (key ++ " = " ++ value) ++ "cannot be parsed."
return $ value == "YES"
crossCompiling :: Action Bool
crossCompiling = flag CrossCompiling
platformSupportsSharedLibs :: Action Bool
platformSupportsSharedLibs = do
badPlatform <- anyTargetPlatform [ "powerpc-unknown-linux"
......
......@@ -23,6 +23,7 @@ import qualified Rules.Perl
import qualified Rules.Program
import qualified Rules.Register
import Settings
import UserSettings (stage1Only)
import Target
import Utilities
......
module Settings (
getArgs, getLibraryWays, getRtsWays, flavour, knownPackages,
findPackageByName, getPkgData, getPkgDataList, isLibrary, stagePackages,
latestBuildStage, programContext, integerLibraryName, getDestDir, stage1Only
latestBuildStage, programContext, integerLibraryName, getDestDir
) where
import Context
......@@ -70,11 +70,6 @@ latestBuildStage pkg = do
stages <- filterM (fmap (pkg `elem`) . stagePackages) [Stage0 ..]
return $ if null stages then Nothing else Just $ maximum stages
-- TODO: Set this from command line
-- | Stage1Only flag.
stage1Only :: Bool
stage1Only = defaultStage1Only
-- | Install's DESTDIR setting.
getDestDir :: Action FilePath
getDestDir = fromMaybe "" <$> cmdInstallDestDir
......@@ -28,7 +28,8 @@ cIncludeArgs = do
path <- getBuildPath
incDirs <- getPkgDataList IncludeDirs
depDirs <- getPkgDataList DepIncludeDirs
mconcat [ arg "-Iincludes"
compilerOrGhc <- package compiler ||^ package ghc
mconcat [ not (crossCompiling && compilerOrGhc) ? arg "-Iincludes"
, arg $ "-I" ++ root -/- generatedDir
, arg $ "-I" ++ path
, pure [ "-I" ++ pkgPath pkg -/- dir | dir <- incDirs ]
......
......@@ -34,8 +34,10 @@ import Settings.Packages.Compiler
import Settings.Packages.Ghc
import Settings.Packages.GhcCabal
import Settings.Packages.Ghci
import Settings.Packages.GhcPkg
import Settings.Packages.GhcPrim
import Settings.Packages.Haddock
import Settings.Packages.Haskeline (haskelinePackageArgs)
import Settings.Packages.IntegerGmp
import Settings.Packages.Rts
import Settings.Packages.RunGhc
......@@ -207,4 +209,6 @@ defaultPackageArgs = mconcat
, integerGmpPackageArgs
, rtsPackageArgs
, runGhcPackageArgs
, disableWarningArgs ]
, disableWarningArgs
, ghcPkgPackageArgs
, haskelinePackageArgs ]
......@@ -7,6 +7,7 @@ import GHC
import Oracles.Flag
import Oracles.Setting
import Settings
import UserSettings (crossCompiling)
compilerPackageArgs :: Args
compilerPackageArgs = package compiler ? do
......@@ -32,6 +33,7 @@ compilerPackageArgs = package compiler ? do
, ghcWithNativeCodeGen ? arg "--flags=ncg"
, ghcWithInterpreter ?
notStage0 ? arg "--flags=ghci"
, crossCompiling ? arg "-f-terminfo"
, ghcWithInterpreter ?
ghcEnableTablesNextToCode ?
notM (flag GhcUnregisterised) ?
......
......@@ -4,10 +4,12 @@ import Context (buildPath)
import GHC
import Expression
import Oracles.Setting
import UserSettings (crossCompiling)
ghcPackageArgs :: Args
ghcPackageArgs = package ghc ? do
stage <- getStage
path <- expr $ buildPath (vanillaContext stage compiler)
mconcat [ builder Ghc ? arg ("-I" ++ path)
, builder GhcCabal ? ghcWithInterpreter ? notStage0 ? arg "--flags=ghci" ]
, builder GhcCabal ? ghcWithInterpreter ? notStage0 ? arg "--flags=ghci"
, builder GhcCabal ? crossCompiling ? arg "-f-terminfo" ]
module Settings.Packages.GhcPkg (ghcPkgPackageArgs) where
import GHC
import Expression
import UserSettings (crossCompiling)
ghcPkgPackageArgs :: Args
ghcPkgPackageArgs = crossCompiling ? package ghcPkg ? builder GhcCabal ? arg "-f-terminfo"
module Settings.Packages.Haskeline (haskelinePackageArgs) where
import Base
import Expression
import GHC
import UserSettings (crossCompiling)
haskelinePackageArgs :: Args
haskelinePackageArgs =
package haskeline ? builder GhcCabal ? crossCompiling ? arg "-f-terminfo"
......@@ -4,7 +4,7 @@
-- accidentally commit them.
module UserSettings (
userBuildRoot, userFlavours, userPackages, verboseCommands,
buildProgressColour, successColour, defaultStage1Only
buildProgressColour, successColour, stage1Only, crossCompiling
) where
import Hadrian.Utilities
......@@ -45,6 +45,11 @@ buildProgressColour = BuildProgressColour (Dull, Magenta)
successColour :: SuccessColour
successColour = SuccessColour (Dull, Green)
-- | Build a cross compiling GHC
-- TODO: Use @Action Bool@ version in @Oracles.Flag@
crossCompiling :: Bool
crossCompiling = False
{-
Stage1Only=YES means:
- don't build ghc-stage2 (the executable)
......@@ -57,5 +62,6 @@ successColour = SuccessColour (Dull, Green)
- (*do* still build all other libraries)
-}
-- | Stage1Only flag, default off
defaultStage1Only :: Bool
defaultStage1Only = False
-- | TODO: Set this dynamically
stage1Only :: Bool
stage1Only = False
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment