wiki:Building/Porting

Version 20 (modified by simonmar, 5 years ago) (diff)

tweaks to new porting docs

Porting GHC

This section describes how to port GHC to a currenly unsupported platform. To avoid confusion, when we say "architecture" we are referring to the processor, and we use the term "platform" to refer to the combination of architecture and operating system.

There are two distinct porting scenarios:

  • Your platform is already supported, but you want to compile up GHC using just a C compiler. This is a straightforward bootstrap from HC files, and is described in the next section.

Booting/porting from C (.hc) files

Bootstrapping GHC on a system without GHC already installed is achieved by taking the intermediate C files (known as HC files) from another GHC compilation, compiling them using gcc to get a working GHC.

NOTE: Versions supported: between 6.0.1 and 6.6.2. We are working on getting bootstrapping working again in the 6.8 series, see #1346.

HC files are platform-dependent, so you have to get a set that were generated on the same platform. There may be some supplied on the GHC download page, otherwise you'll have to compile some up yourself.

The following steps should result in a working GHC build with full libraries:

  • Make a set of HC files. On an identical system with GHC already installed, get a GHC source tree and put the following in mk/build.mk:
    SRC_HC_OPTS     = -H32m -O -fvia-C -Rghc-timing -keep-hc-files
    GhcLibHcOpts    = -O
    GhcLibWays      =
    SplitObjs       = NO
    
    Build GHC as normal, and then make hc-file-bundle Project=ghc to creates the tar file containing the hc files.
  • On the target system, unpack the HC files on top of a fresh source tree (make sure the source tree version matches the version of the HC files exactly!). This will place matching .hc files next to the corresponding Haskell source (.hs or .lhs) in the compiler subdirectory ghc/compiler and in the libraries (subdirectories of libraries).
  • The actual build process is fully automated by the distrib/hc-build script. If you eventually want to install GHC into the directory <dir>, the following command will execute the whole build process (it won't install yet):
    $ distrib/hc-build --prefix=<dir>
    
    By default, the installation directory is /usr/local. If that is what you want, you may omit the argument to hc-build. Generally, any option given to hc-build is passed through to the configuration script configure. If hc-build successfully completes the build process, you can install the resulting system, as normal, with
    $ make install
    

Porting GHC to a new platform

NOTE: Versions supported: 6.11+.

The first step in porting to a new platform is to get an unregisterised build working. An unregisterised build is one that compiles via vanilla C only. This costs about a factor of two in performance, but since unregisterised compilation is usually just a step on the way to a full registerised port, we don't mind too much.

You should go through this process even if your architecture is already has registerised support in GHC, but your OS currently isn't supported. In this case you probably won't need to port any of the architecture-specific parts of the code, and you can proceed straight from the unregisterised build to build a registerised compiler.

Notes on GHC portability in general: we've tried to stick to writing portable code in most parts of the system, so it should compile on any POSIXish system with gcc, but in our experience most systems differ from the standards in one way or another. Deal with any problems as they arise - if you get stuck, ask the experts on glasgow-haskell-users@….

Lots of useful information about the innards of GHC is available in the Commentary, which might be helpful if you run into some code which needs tweaking for your system.

Cross-compiling to produce an unregisterised GHC

NOTE! These instructions apply to GHC 6.11 and (hopefully) later.

In this section, we explain how to bootstrap GHC on a new platform, using unregisterised intermediate C files. We haven't put a great deal of effort into automating this process, for two reasons: it is done very rarely, and the process usually requires human intervention to cope with minor porting issues anyway.

The following step-by-step instructions should result in a fully working, albeit unregisterised, GHC. Firstly, you need a machine that already has a working GHC (we'll call this the host machine), in order to cross-compile the intermediate C files that we will use to bootstrap the compiler on the target machine.

On the target machine

Unpack a source tree (preferably a released version). We will call the path to the root of this tree <T>.

<T>$ sh boot
<T>$ ./configure --enable-hc-boot

You might need to update configure.ac to recognise the new platform, and re-generate configure with autoreconf.

<T>$ make bootstrapping-files

On the host machine

Unpack a source tree (exactly the same version as before). Call this directory <H>.

<H>$ sh boot
<H>$ ./configure

Create <H>/mk/build.mk, with the following contents:

GhcUnregisterised = YES
GhcLibHcOpts = -O -fvia-C -keep-hc-files
GhcRtsHcOpts = -keep-hc-files
GhcLibWays = v
SplitObjs = NO
GhcWithNativeCodeGen = NO
GhcWithInterpreter = NO
GhcStage1HcOpts = -O
GhcStage2HcOpts = -O -fvia-C -keep-hc-files
SRC_HC_OPTS += -H32m
GhcWithSMP = NO

Edit <H>/mk/project.mk:

  • change TARGETPLATFORM appropriately, and set the variables involving TARGET or Target to the correct values for the target platform. This step is necessary because currently configure doesn't cope with specifying different values for the --host and --target flags.
  • copy LeadingUnderscore setting from target.

Copy <T>/includes/ghcautoconf.h, <T>/includes/DerivedConstants.h, and <T>/includes/GHCConstants.h to <H>/includes. Note that we are building on the host machine, using the target machine's configuration files. This is so that the intermediate C files generated here will be suitable for compiling on the target system.

Now build the compiler:

<H>$ make

You may need to work around problems that occur due to differences between the host and target platforms.

<H>$ rm -f list mkfiles boot.tar.gz
<H>$ find . -name "*.hc" >> list
<H>$ find . -name "*_stub.*" >> list
<H>$ find . -name package-data.mk >> list
<H>$ find . -name package.conf >> list
<H>$ find . -name package.conf.inplace >> list
<H>$ echo compiler/main/Config.hs >> list
<H>$ find . -name .depend | sed -e 's/^/mkdir -p `dirname /' -e 's/$/`/' >> mkfiles
<H>$ find . -name .depend | sed "s/^/touch /" >> mkfiles
<H>$ echo mkfiles >> list
<H>$ tar -zcf boot.tar.gz -T list

On the target machine

<T>$ cp /bin/pwd utils/ghc-pwd/ghc-pwd
<T>$ sh boot
<T>$ ./configure --enable-hc-boot

Unpack <H>/boot.tar.gz to <T>/.

<T>$ tar --touch -zxf boot.tar.gz
<T>$ sh mkfiles

Put this in <T>/mk/build.mk:

GHC = false
GHC_PKG_INPLACE =
GHC_CABAL_INPLACE =
DUMMY_GHC_INPLACE =
UNLIT =
NO_INCLUDE_DEPS = YES
GhcUnregisterised = YES
GhcLibWays = v
SplitObjs = NO
GhcWithNativeCodeGen = NO
GhcWithInterpreter = NO
GhcWithSMP = NO
ghc_stage2_v_EXTRA_CC_OPTS += -Lgmp -lgmp -lm -lutil -lrt
<T>$ for c in libraries/*/configure; do ( cd `dirname $c`; ./configure ); done
<T>$ sed -i .bak "s#<H>#<T>#g" */*/package-data.mk */*/*/package-data.mk
<T>$ touch -r compiler/stage2/package-data.mk */*/package-data.mk */*/*/package-data.mk

Now make bootstrapping files; what we're really doing here is making libffi, and libgmp if necessary:

<T>$ make bootstrapping-files
<T>$ make all_ghc_stage2 2>&1 | tee log

Don't bother with running make install in the newly bootstrapped tree; just use the compiler in that tree to build a fresh compiler from scratch, this time without booting from C files. Before doing this, you might want to check that the bootstrapped compiler is generating working binaries:

$ cat >hello.hs
main = putStrLn "Hello World!\n"
^D
$ <T>/inplace/bin/ghc-stage2 hello.hs -o hello
$ ./hello
Hello World!

Once you have the unregisterised compiler up and running, you can use it to start a registerised port. The following sections describe the various parts of the system that will need architecture-specific tweaks in order to get a registerised build going.

Porting the RTS

The following files need architecture-specific code for a registerised build:

includes/MachRegs.h:

Defines the STG-register to machine-register mapping. You need to know your platform's C calling convention, and which registers are generally available for mapping to global register variables. There are plenty of useful comments in this file.

includes/TailCalls.h
Macros that cooperate with the mangler (see The mangler) to make proper tail-calls work.
rts/Adjustor.c
Support for foreign import "wrapper". Not essential for getting GHC bootstrapped, so this file can be deferred until later if necessary.
rts/StgCRun.c
The little assembly layer between the C world and the Haskell world. See the comments and code for the other architectures in this file for pointers.
rts/MBlock.h, rts/MBlock.c
These files are really OS-specific rather than architecture-specific. In MBlock.h is specified the absolute location at which the RTS should try to allocate memory on your platform (try to find an area which doesn't conflict with code or dynamic libraries). In Mblock.c you might need to tweak the call to mmap() for your OS.

The mangler

The mangler is an evil Perl-script (driver/mangler/ghc-asm.lprl) that rearranges the assembly code output from gcc. To understand what the manger does and how it works, see Commentary/EvilMangler.

The mangler is abstracted to a certain extent over some architecture-specific things such as the particular assembler directives used to herald symbols. Take a look at the definitions for other architectures and use these as a starting point for porting it to your platform.

The splitter

The splitter is another evil Perl script (driver/split/ghc-split.lprl). It cooperates with the mangler to support object splitting. Object splitting is what happens when the -split-objs option is passed to GHC: the object file is split into many smaller objects. This feature is used when building libraries, so that a program statically linked against the library will pull in less of the library.

The splitter has some platform-specific stuff; take a look and tweak it for your system.

The native code generator

The native code generator isn't essential to getting a registerised build going, but it's a desirable thing to have because it can cut compilation times in half. The native code generator is described in detail in Commentary/Compiler/Backends/NCG.

GHCi

To support GHCi, you need to port the dynamic linker (rts/Linker.c). The linker currently supports the ELF and PEi386 object file formats - if your platform uses one of these then things will be significantly easier. The majority of Unix platforms use the ELF format these days. Even so, there are some machine-specific parts of the ELF linker: for example, the code for resolving particular relocation types is machine-specific, so some porting of this code to your architecture and/or OS will probably be necessary.

If your system uses a different object file format, then you have to write a linker -- good luck!