8

I'm trying to call Haskell from c++.

I tried to use this explanation; and already asked one question on SO.

However, I haven't got any answer so I'd like to reformulate to a Minimal, Complete, and Verifiable example.

I'm using Debian and this is what I have (In the same folder):

c++:

// main.cpp
#include <iostream>
#include "Hello_stub.h"

int main(int argc, char** argv) {
  hs_init(&argc, &argv);
  std::cout << "Hello from C++\n";
  helloFromHaskell();
  hs_exit();
  return 0;
}

Haskell:

// hello.hs
module Hello where

foreign export ccall helloFromHaskell :: IO ()

helloFromHaskell :: IO ()
helloFromHaskell = putStrLn "Hello from Haskell"

MakeFile:

CPP_SOURCES = main.cpp
HASKELL_SOURCES = Hello.hs
CFLAGS = -Wall -g -fno-stack-protector
HFLAGS = -fforce-recomp

all: main; ./main

main: $(CPP_SOURCES) HaskellPart; g++ \
    $(CFLAGS) -o main $(CPP_SOURCES) Hello.o \
    -I/usr/lib/ghc/include \
    -liconv \
    -I/usr/lib/ghc/ghc-8.0.1/include \
    -L/usr/lib/ghc/ghc-8.0.1 \
    -L/usr/lib/ghc/base-4.9.0.0 \
    -lHSbase-4.9.0.0 \
    -L/usr/lib/ghc/ghc-prim-0.5.0.0 \
    -lHSghc-prim-0.5.0.0 \
    -L/usr/lib/ghc/integer-gmp-1.0.0.1 \
    -lHSinteger-gmp-1.0.0.1 \
    -lHSghc-prim-0.5.0.0 \
    -L/usr/lib/ghc/rts \
    -lHSrts \

HaskellPart: $(HASKELL_SOURCES); ghc $(HFLAGS) $(HASKELL_SOURCES)

clean: ; rm -rf main && rm -rf *.o && rm -rf *.hi && rm -rf *_stub.h

Here's the output. It seems to be a bunch of errors of the form

/usr/bin/ld: Hello.o: relocation R_X86_64_32S against symbol `stg_bh_upd_frame_info' can not be used when making a shared object; recompile with -fPIC

What's wrong? Thank you for your help !

Community
  • 1
  • 1
Maxime VAST
  • 540
  • 6
  • 22
  • 1
    I just spent all day doing this yesterday, and succeeded, so it is possible. I didn't hit the error you are seeing, but the errors seem to be telling you to add `-fPIC` to your compiler flags. (I hope it doesn't mean when compiling GHC) – luqui Mar 29 '17 at 18:17
  • 2
    Another option (which wasn't available to me) that I heard worked is to use `ghc` as your linker. Then you don't need to futz with all the `-L` stuff. I.e. `g++ -c main.cpp; ghc Hello.hs main.o -o main` or something – luqui Mar 29 '17 at 18:23
  • @luqui Thank you for taking the time. Do you have any link for this other option? About -fPIC, I have tried to add it but it doesn't change anything. My guess is that the error come from the libraries and not from the compilation of my code. Do you have any working example ? Could you kindly share? Regards – Maxime VAST Mar 29 '17 at 18:25
  • I don't know how much [my example](https://github.com/luqui/lukeper) is going to help, it's a pretty different context. OSX on Xcode. But the linker flags are [here](https://github.com/luqui/lukeper/blob/master/Builds/MacOSX/lukeper.xcodeproj/project.pbxproj#L3894) – luqui Mar 29 '17 at 18:27
  • Wait -- there seem to be some errors in your makefile. You talk about `HaskellPart.o` but there's no `HaskellPart.hs`. And `Hello.o` is on the `g++` command line despite ostensibly requiring `HaskellPart.o`. Clean out your project directory and try again (so your won't be misled by stale object files). Also shouldn't `-c` be on the `ghc` command line? – luqui Mar 29 '17 at 18:32
  • @luqui Thanks for the linker flags. `HaskellPart.o` is the instruction compiling `Hello.hs`, not a file. What `-c`? – Maxime VAST Mar 29 '17 at 18:41
  • Oh, I see. That's very misleading -- it looks like a file. `-c` says to compile only the object file (`.o`) and not try to make an executable program. Maybe it's the default if there's no output `-o` or `--make` flag. – luqui Mar 29 '17 at 18:50
  • @luqui Yeah I understand. I have rename it to keep things clear. I'm desperate to find a solution :/ – Maxime VAST Mar 29 '17 at 18:57
  • 1
    things take as long as they take. One step at a time. ;-) – luqui Mar 29 '17 at 18:58

1 Answers1

2

Not sure whether that's actually in your file or whether it's just in the version you put in your question but "// hello.hs" won't compile. Comments are -- in Haskell not //.

Anyway on to the interesting part...

First you need to import the HsFFI.h header file into your C++ code.

#include <iostream>
#include "Hello_stub.h"
#include <HsFFI.h>

Then use ghc to link the files after compiling them. Open a command prompt / terminal and navigate the directory containing your C++ and Haskell files. Then run the following commands:

ghc -c -XForeignFunctionInterface -O hello.hs
g++ -c -O main.cpp -I "C:\Program Files\Haskell Platform\7.10.3\lib\include"                         
ghc -no-hs-main hello.o main.o -lstdc++

The filepath in the second command is to the directory containing the HsFFI.h file.

Running main then outputs:

Hello from C++
Hello from Haskell
James Burton
  • 746
  • 3
  • 12
  • Awesome, thank you so much ! Would you say that the github tutorial is wrong or only adapted to mac os? Do you have any further explanation? – Maxime VAST Mar 30 '17 at 08:42
  • 1
    @MaximeVAST I can't really say because I don't know a huge amount about CMake. The tutorial is from 2014 so it might just be outdated. Try adding -shared and -dynamic (maybe -fPIC as well) to your Haskell flags in the CMake file and see if your original method works then. – James Burton Mar 31 '17 at 19:36