3
votes

I made a short Haskell-program that exposes functions for C or Python. Followed http://www.haskell.org/ghc/docs/7.0.3/html/users_guide/ffi-ghc.html#ffi-library to the letter and that worked okay for exporting Ints.

Want to export Strings and made the program:

module Adder where

import CString

adder :: Int -> Int -> IO CString 
adder x y =  newCString(show(x+y))

foreign export ccall adder :: Int -> Int -> IO CString

That compiles okay when I do : ghc adder.hs but it fails when linking to create a dll in Windows.

ghc -shared -o adder.dll adder.o adder_stub.o StartEnd.o

The error: adder.o:fake:(.text+0x11d): undefined reference to `__stginit_haskell98zm1zi1zi0zi1_CString_'

The StartEnd.o is compiled from the C-file that I copied from the haskell.org-site :

#include <Rts.h>
extern void __stginit_Adder(void);
void HsStart()
{
  int argc = 1;
  char* argv[] = {"ghcDll", NULL}; // argv must end with NULL
  // Initialize Haskell runtime
  char** args = argv;
  hs_init(&argc, &args);
  // Tell Haskell about all root modules
  hs_add_root(__stginit_Adder);
}
void HsEnd()
{
  hs_exit();
}

What must I do to be able to export Strings ??

1
Just as a note, I would avoid the f(g(x)) style and use either f (g x) or f $ g x or f . g $ xalternative

1 Answers

2
votes

Try to import Foreign.C.String instead of the module CString. GHC should recognize the module and link in the correct library. On a Linux system, compiling static, I had the same issue you did (undefined ref). When I altered that import, leaving me with the below code, everything worked.

My Haskell module (exporting functions):

$ cat so.hs
module Adder where

import Foreign.C.String

adder :: Int -> Int -> IO CString 
adder x y =  newCString(show(x+y))

foreign export ccall adder :: Int -> Int -> IO CString

My main C file (Which includes all the init and take down work inline, not pretty but this is just educational):

$ cat soMain.c
#include <Rts.h>
#include "so_stub.h"

extern void __stginit_Adder(void);

void main()
{
  char *str = NULL;
  int argc = 1;
  char* argv[] = {"ghcDll", NULL}; // argv must end with NULL
  // Initialize Haskell runtime
  char** args = argv;
  hs_init(&argc, &args);
  // Tell Haskell about all root modules
  hs_add_root(__stginit_Adder);

  // END INIT


  str = adder(1,2);
  printf("%s\n",str);

  // END MAIN START THE FINALIZERS
  hs_exit();


}

My commands:

$ ghc -c so.hs
$ ghc soMain.c so_stub.o so.o -o so -fforce-recomp
$ ./so
3

EDIT: Just a guess, but perhaps the CString import would work if you specified {-# LANGUAGE Haskell98, ForeignFunctionInterface #-}