15

I've successfully created a ghc cross compiler, that allows me to compile haskell code for armv6h (raspberry pi in my case) from my x64 linux machine. I've successfully run a hello world program on the raspberry.

No I want to build my real app, which has a lot of dependencies on other haskell modules. When I compile for x64 I simply do

cabal install dependenciy1 depenency2 ...

I know I could make my own programm a cabal-project an automate this step. But that's not the point here.

When I try to use the cross-compiler

arm-unknown-linux-gnueabi-ghc --make myapp.hs

It tells me about modules it could not find. Of course, they are not installed!

I read https://ghc.haskell.org/trac/ghc/wiki/Building/CrossCompiling and according to that I tried

cabal --with-ghc=arm-unknown-linux-gnueabi-ghc --with-ghc-pkg=arm-unknown-linux-gnueabi-ghc-pkg --with-ld=arm-unknown-linux-gnueabi-ld install random

random is the depenency I'm trying to install here. I get the following error:

Resolving dependencies...
Configuring random-1.0.1.3...
Failed to install random-1.0.1.3
Last 10 lines of the build log ( /home/daniel/.cabal/logs/random-1.0.1.3.log ):
/home/daniel/.cabal/setup-exe-cache/setup-Cabal-1.18.1.3-arm-linux-ghc-7.8.3.20140804: /home/daniel/.cabal/setup-exe-cache/setup-Cabal-1.18.1.3-arm-linux-ghc-7.8.3.20140804:      cannot execute binary file
cabal: Error: some packages failed to install:
random-1.0.1.3 failed during the configure step. The exception was:
ExitFailure 126

When I do

file /home/daniel/.cabal/setup-exe-cache/setup-Cabal-1.18.1.3-arm-linux-ghc-7.8.3.20140804

I get

/home/daniel/.cabal/setup-exe-cache/setup-Cabal-1.18.1.3-arm-linux-ghc-7.8.3.20140804: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 3.10.2, not stripped

No wonder it can't execute it. It's compiled for arm.

Am I missing something here? My goal is to pull in all dependencies, then create a statically linked app that I can deploy on my raspberry.

Daniel Schmitz
  • 347
  • 1
  • 7
  • 2
    can you try `cabal get random`, then cd to the `random-???` directory, and then `runhaskell ./Setup.hs install --with-ghc=... ...` ? – bennofs Sep 10 '14 at 13:41
  • When I do that I get `unrecognized 'install' option \`--with-ghc=arm-unknown-linux-gnueabi-ghc' unrecognized 'install' option \`--with-ghc-pkg=arm-unknown-linux-gnueabi-ghc-pkg' unrecognized 'install' option \`--with-ld=arm-unknown-linux-gnueabi-ld'` – Daniel Schmitz Sep 10 '14 at 13:50
  • Oh, seems you need to do `runhaskell ./Setup.hs configure --with...`, then `runhaskell ./Setup.hs build` and finally `runhaskell ./Setup.hs install`. – bennofs Sep 10 '14 at 13:56
  • okay, that seems to work. But now when I try to link my app against it, the linker says: `/home/daniel/x-tools/arm-unknown-linux-gnueabi/lib/gcc/arm-unknown-linux-gnueabi/4.8.2/../../../../arm-unknown-linux-gnueabi/bin/ld: skipping incompatible /home/daniel/.cabal/lib/arm-linux-ghc-7.8.3.20140804/random-1.0.1.3/libHSrandom-1.0.1.3.a when searching for -lHSrandom-1.0.1.3` – Daniel Schmitz Sep 10 '14 at 14:20
  • 1
    @DanielSchmitz Try to disabling stripping when configuring, `--disable-library-stripping` and `--disable-executable-stripping` – Yuras Sep 10 '14 at 14:25
  • @bennofs you probably should make a real answer to let us upvote it – Yuras Sep 10 '14 at 14:29
  • 1
    Also, if the package uses `hsc2hs`, make sure it gets `-x` flag, otherwise it will produce `Storable` instances for host architecture instead of target. IIRC I needed it for `network`, otherwise it crashed at runtime. – Yuras Sep 10 '14 at 14:35
  • @Yuras: disabling stripping did it. I can now compile and link a static binary and execute it on the pi :-) – Daniel Schmitz Sep 10 '14 at 14:37

1 Answers1

11

To understand this error, you need to know how cabal install works internally. In essence, it will perform the following steps:

  1. Download and unpack the source code
  2. Compile Setup.hs (this file is used for customization of the build system, for example, you can implement some hooks to run additional haskell code in the configure phase).
  3. Run setup configure <configure flags> && setup build && setup install

The problem is now that cabal install uses the GHC given by --with-ghc also for step 2, but the executable produced by that step must run on the host system!

A workaround is to do the steps manually, which means you have full control. First, get the source:

$ cabal get random
Downloading random-1.0.1.3...
Unpacking to random-1.0.1.3/
$ cd random-1.0.1.3

Then, compile Setup.hs, using the host ghc:

$ ghc ./Setup.hs -o setup

And finally, configure, build and install. As suggested by @Yuras in a comment, we also add the -x option for running hsc2hs:

$ ./setup configure ----with-ghc=arm-unknown-linux-gnueabi-ghc --with-ghc-pkg=arm-unknown-linux-gnueabi-ghc-pkg --with-ld=arm-unknown-linux-gnueabi-ld --hsc2hs-options=-x
$ ./setup build && ./setup install

There is already a cabal issue about this: https://github.com/haskell/cabal/issues/2085

bennofs
  • 11,873
  • 1
  • 38
  • 62
  • Should `ghc ./Setup.hs -osetup` be `ghc ./Setup.hs -o setup` with a space between `-o` and `setup`? I received `unrecognised flags: -osetup` without the space. – HeatfanJohn Sep 18 '14 at 22:33
  • @HeatfanJohn Oh, that's surprising, you indeed need a space. I wonder why `-packagelens` works without a space then though ... – bennofs Sep 19 '14 at 11:26
  • Is there actually a way to simulate what cabal is doing in a script? It would be helpful to be able to specify `builddir` option and have support for sandboxes... – Alexey Raga Apr 04 '15 at 06:21