2
votes

My project uses FFI, so I always have to link against precompiled object files testing with GHCi:

ghci Foo a.o

My question is: Is there a way to do this once GHCi is running instead of GHCi startup? I've tried this:

$ ghci
> :l Foo a.o

but I get the error a.o is not a module name or a source file

My goal for this is to be able to start a GHCi session with external symbols linked in via a .ghci file. My motivation is that cabal compiles the object files into dist/build/my-tests/my-tests-tmp/src/../../../../a.o, which ends up being 92 characters long. It's bad enough to have to type this once (with a *,o at the end), but due to a regression in GHC 7.8, I have to link five object files in a specific order which requires over 500 characters after ghci Foo.

** UPDATE **

The following example demonstrates why n.m.'s solution below isn't working for me on GHC 7.8.2:

mul.c

#include <inttypes.h>
void mulRq (int64_t* a, int64_t* b, int32_t totm, int64_t q) { }

Mul.hs

module Mul where

import Data.Int
import Foreign.Ptr

foreign import ccall unsafe "mulRq" mulRq :: 
  Ptr Int64 -> Ptr Int64 -> Int64 -> Int64 -> IO ()

Dummy.hs is empty.

Steps:

  1. ghci Mul

    [can't find label mulRq]

  2. gcc -c -o mul.o mul.c
  3. ghci Mul mul.o

    [ghci loads]

  4. ghci -fobject-code Dummy
  5. ghci Dummy

    [ghci loads without compiling]

  6. ld -r Dummy.o mul.o -o temp.o
  7. mv temp.o Dummy.o
  8. ghci Dummy

    [ghci loads without compiling]

  9. nm Dummy.o

    [verify that Dummy.o contains the symbol mulRq]

Now start ghci:

$ ghci
GHCi, version 7.8.2: 
...
Prelude> :l Dummy
Ok, modules loaded: Main.
Prelude Main> :l Mul
[1 of 1] Compiling Mul              ( Mul.hs, interpreted )

ByteCodeLink: can't find label
During interactive linking, GHCi couldn't find the following symbol:
  mulRq
1
Use a shell script instead of a .ghci?Ry-♦
Can you wrap the objects in dummy Haskell/ghc modules?n. 1.8e9-where's-my-share m.
You can also have a .ghci file on a per-project basis that you can set up to load the object files you need just for that project. It'll load them all when you start GHCi, but at least you can control it more for whatever project you're working on and don't have to have them global.bheklilr
@n.m. Sounds interesting...how would I do that?crockeea
@bheklilr I do have a per-project .ghci file. That's exactly what I'm asking: how do I set it up to load the object files at the start of GHCi?crockeea

1 Answers

1
votes
  1. Compile a Haskell module Dummy.hs into Dummy.o. It can be totally empty, or contain any useful Haskell code.
  2. Make sure ghci Dummy loads an existing compiled version of Dummy (does not print Compiling when loading it).
  3. Combine Dummy.o and a.o:

    ld -r Dummy.o a.o -o temp.o
    mv temp.o Dummy.o

  4. Now you have a loadable Haskell module Dummy that also contains all of the a.o.

Update

This scheme works if modules that use a.o/Dummy.o are compiled to object code, and does not work if they are interpreted.

A simple way to always use compiled code is to run GHCi with -fobject-code. Using your example,

ghci -fobject-code
Prelude> :l Dummy
Ok, modules loaded: Dummy.
Prelude Dummy> :l Mul
[1 of 1] Compiling Mul              ( Mul.hs, Mul.o )
Ok, modules loaded: Mul.
Prelude Mul>