porting to uClibc-based 686 Linux

Dubiousjim lists+haskell-glasgow at jimpryor.net
Wed Apr 3 15:56:58 CEST 2013

I've gotten somewhat further cross-compiling 7.6.2 sources, though
still not all the way.

I also tried following the instructions at
with these sources, but couldn't get them to work either.

This continues to log my efforts to follow the instructions at

One thing I notice by comparing the 7.6.2 sources and the pre-release
sources available at 
is that the instructions at the wiki webpage just cited are tailored
to the post-7.6.2 sources. Some of the configure settings should be
different for 7.6.2.

In particular, I had been using this:

is that the instructions at the wiki webpage just cited are tailored
to the post-7.6.2 sources. Some of the configure settings should be
different for 7.6.2.

In particular, I had been using this:

./configure --target=i686-buildroot-linux-uclibc --disable-largefile

as the wiki pages seem to suggest. But now I see that I should also be
setting --host for 7.6.2, and also supplying an --alien=<script> option.

The latter is a script you need to write which will run on the host and
take arguments of the form "run <cmd> <more arguments...>". It should
then copy "<cmd>" to the target machine and execute "<cmd> <more
arguments...>" there, passing through its stdout.

Here is the alien script I'm using:

    #!/bin/sh -x
    shift 2
    scp "$CMD" ${USER}@${TARGET}:alien.cache/
    ssh ${USER}@${TARGET} alien.cache/"${CMD##*/}" "$@"

That relies on the presence of a folder alien.cache in ${USER}'s home
directory on the target machine. It also relies on your being able to
ssh from host to target without requiring a password.

This script seems to be invoked twice during my builds, for
There's a third time I think it should be invoked but isn't, and then I
have to invoke it manually. (This is explained below.)

So here are the steps I'm following now. Most everything described in my
preceding email still seems to be necessary; I'm including those steps
here as well.

> To refresh, I'm trying to bootstrap from a working ghc (now I have 7.6.2
> installed on the host) on a typical Linux 686 host system, glibc-based,
> to get a ghc that can be installed on a similar target system, differing
> in that it uses uclibc instead of glibc.
> I have a working cross-compiler, and seem to have everything else I need
> to have installed on my host. I did have to make sure that my
> cross-compiler tree had gmp and libiconv and ncurses installed in it.
> I also had to edit the file /usr/lib/ghc-7.6.2/include/ghcautoconf.h
> on my host system. This was #defining _FILE_OFFSET_BITS to 64, but the
> uclibc on my target system wasn't compiled with large file support,
> hence I thought the uclibc in my cross-compiler toolchain shouldn't be
> either. But then that #define in the host's ghcautoconf.h was
> conflicting. So I just commented it out for the time being.
> Here's what I've done, on the host, from a clean detar of the ghc 7.6.2
> sources.
> I made this change at three locations in ghc's topmost
> configure script, to get it to recognize my cross-compiler tag 
> "i686-buildroot-linux-uclibc":
>        case "$build_vendor" in
>     -  pc|gentoo) # like i686-pc-linux-gnu and i686-gentoo-freebsd8
>     +  pc|gentoo|buildroot) # like i686-pc-linux-gnu and
>     i686-gentoo-freebsd8
>          BuildVendor="unknown"
>          ;;
> (The other two locations are for $host_vendor and $target_vendor. Maybe
> it's only necessary to do this for $target_vendor.)
> Next, here is my mk/build.mk file:
>     # Fast build with optimised libraries, no profiling (RECOMMENDED):
>     BuildFlavour = quick
>     ...
>     # An unregisterised, optimised build of ghc, for porting:
>     # BuildFlavour = unreg
>     ...
> The rest as in mk/build.mk.sample

> Next, the configure scripts for
> libraries/{base,directory,integer-gmp,old-time,process,terminfo,time,unix}
> would stall, complaining that the C compiler didn't generate
> binaries they could execute. I fixed that by patching those configure
> scripts like this---I don't know if this is correct, it may be the
> source of my later troubles. On the other hand, I don't know how else
> to get past the configure scripts failing. Adding switches like --host
> and --host="" to my original configure, as an error message suggests,
> seems to have no effect.
>     @@ -2833,7 +2833,7 @@
>        test $ac_status = 0; }; }; then
>          cross_compiling=no
>        else
>     -    if test "$cross_compiling" = maybe; then
>     +    if true || test "$cross_compiling" = maybe; then
>      	cross_compiling=yes
>          else
>      	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in
>      	\`$ac_pwd':" >&5

> Next, I had to make this patch to libraries/haskeline/cbits/h_wcwidth.c,
> else I would get errors about types like size_t not being recognized. (I
> forget the exact error.)
>     @@ -59,6 +59,7 @@
>       * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
>       */
>     +#include <stddef.h>
>      #include <wchar.h>
>      struct interval {

Here is the actual error message this patch avoids:

      HC [stage 1]
         error: unknown type name 'wchar_t'
         error: unknown type name 'wchar_t'
         error: unknown type name 'wchar_t'
         error: unknown type name 'size_t'
         error: unknown type name 'wchar_t'
         error: unknown type name 'wchar_t'
         error: unknown type name 'size_t'

Ok, so here are the steps I'm currently using to configure and build:

    export PATH=${PATH}:/path/to/my/cross-compiler
    make distclean
    ./configure --host=i686-buildroot-linux-uclibc \
    --target=i686-buildroot-linux-uclibc --disable-largefile \

As I mentioned in my previous email, at a certain point the build tries
to execute:

    libraries/integer-gmp/cbits/mkGmpDerivedConstants > \

where the first is a binary it generated using the cross-compiler. This
won't run on the host system. Now we can run it by issuing the following
command on the host:

    /path/to/alien run libraries/integer-gmp/cbits/mkGmpDerivedConstants
    > \

As I also mentioned in my previous email, the build will also fail
unless I add the following lines to

    #define HTYPE_DOUBLE Double
    #define HTYPE_FLOAT Float

That's based on what I see in my host system. The HsBaseConfig.h file
is only generated during the build, so you can't make this change ahead
of time; you have to wait for the build to fail, make the change, and
then reissue "make".

Now, with the new configure options, this build continues past stage1
and proceeds to build stage2 as well.

However, it gets stuck while trying to build these binaries:

It gets stuck because it tries to execute the
inplace/lib/ghc-stage2 it has built, but this will only run on the
target machine.

What a pain. I was able to hack around this in an ugly way. I'll explain
what I did, but it depends on the fact that my host environment is a
chroot inside my target. You don't want to do this at home.

So inside my home directory on the TARGET environment, I did this.
CROSSPATH is the absolute path to my cross-compiler
i686-buildroot-linux-uclibc-gcc in my host environment (that is, where /
is the base of the chroot, not the base of the target's filesystem).
GHCSOURCE is the absolute path to my ghc-7.6.2 source tree in the same
host environment.

    mkdir -p ${CROSSPATH%/*}
    ln -s `which gcc` ${CROSSPATH}
    ln -s /path/on/target/to/host/chroot/$GHCSOURCE/libraries

Then inside the ghc-7.6.2 folder in the host environment, I moved
inplace/lib/ghc-stage2 to inplace/lib/ghc-stage2.exe and installed the
following script as inplace/lib/ghc-stage2:

    #!/bin/sh -x
    ssh ${USER}@${TARGET} "${CMD}.exe" "$@"

I also had to make $GHCSOURCE on my target machine be a symlink to

This will get me a bit further in the make process. There are two
commands that fail even this way, and that I have to run manually on the
target machine, to build utils/ghctags/dist-install/build/Main.o.

Ok, with all of that, the build completes. And the build ghc-stage2
(which I temporarily named inplace/lib/ghc-stage2.exe, but now let's
restore it to its original name) does in fact execute on the target

    $ inplace/lib/ghc-stage2 --version
    The Glorious Glasgow Haskell Compilation System, version 7.6.2
    $ inplace/lib/ghc-stage2 --interactive
    ghc-stage2: missing -B<dir> option
    $ inplace/lib/ghc-stage2 -B./inplace/lib --interactive
    GHCi, version 7.6.2: http://www.haskell.org/ghc/  :? for help
    Loading package ghc-prim ... ghc-stage2: mmap 442368 bytes at (nil):
    Operation not permitted
    ghc-stage2: Try specifying an address with +RTS -xm<addr> -RTS
    $ cat ~/hello.hs
    main = putStrLn "Hello World!\n"
    $ inplace/lib/ghc-stage2 -B./inplace/lib ~/hello.hs -o hello
    $ ./hello
    Can't modify application's text section; use the GCC option -fPIE
    position-independent executables.

That's as far as I've got for now. Hopefully someone will have
bothered to read this far and have some suggestions for what I should be
doing differently, or how to proceed from here, to get the compiled
ghc-stage2 really working on the target machine, so that I can use it to
compile ghc on the target machine directly.

dubiousjim at gmail.com

More information about the Glasgow-haskell-users mailing list