How do I install dependencies when cross compiling haskell code?
Asked Answered
O

1

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.

Obstetrics answered 10/9, 2014 at 12:48 Comment(8)
can you try cabal get random, then cd to the random-??? directory, and then runhaskell ./Setup.hs install --with-ghc=... ... ?Electrocardiogram
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'Obstetrics
Oh, seems you need to do runhaskell ./Setup.hs configure --with..., then runhaskell ./Setup.hs build and finally runhaskell ./Setup.hs install.Electrocardiogram
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.3Obstetrics
@DanielSchmitz Try to disabling stripping when configuring, --disable-library-stripping and --disable-executable-strippingSixtyfourmo
@Electrocardiogram you probably should make a real answer to let us upvote itSixtyfourmo
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.Sixtyfourmo
@Yuras: disabling stripping did it. I can now compile and link a static binary and execute it on the pi :-)Obstetrics
E
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

Electrocardiogram answered 10/9, 2014 at 15:17 Comment(3)
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.Cacka
@Cacka Oh, that's surprising, you indeed need a space. I wonder why -packagelens works without a space then though ...Electrocardiogram
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...Forsta

© 2022 - 2024 — McMap. All rights reserved.