Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compile Haskell to a static library?

Hey, I'm learning Haskell and I'm interested in using it to make static libraries for using in Python and probably C. After some googling I found out how to get GHC to output a shared object, but it dynamically depends on GHC`s libraries. The resulting ELF from compiling in GHC is dynamically dependand only on C libs and it's a bit under a MB in size - it has been statically linked with GHC`s libs. How and if can this be achieved for shared objects?

Example of current state:

$ ghc --make -dynamic -shared -fPIC foo.hs -o libfoo.so $ ldd libfoo.so     linux-vdso.so.1 =>  (0x00007fff125ff000)     libHSbase-4.2.0.2-ghc6.12.3.so => /usr/lib/ghc-6.12.3/base-4.2.0.2/libHSbase-4.2.0.2-ghc6.12.3.so (0x00007f7d5fcbe000)     libHSinteger-gmp-0.2.0.1-ghc6.12.3.so => /usr/lib/ghc-6.12.3/integer-gmp-0.2.0.1/libHSinteger-gmp-0.2.0.1-ghc6.12.3.so (0x00007f7d5faac000)     libgmp.so.10 => /usr/lib/libgmp.so.10 (0x00007f7d5f816000)     libHSghc-prim-0.2.0.0-ghc6.12.3.so => /usr/lib/ghc-6.12.3/ghc-prim-0.2.0.0/libHSghc-prim-0.2.0.0-ghc6.12.3.so (0x00007f7d5f591000)     libHSffi-ghc6.12.3.so => /usr/lib/ghc-6.12.3/libHSffi-ghc6.12.3.so (0x00007f7d5f383000)     libc.so.6 => /lib/libc.so.6 (0x00007f7d5f022000)     /lib/ld-linux-x86-64.so.2 (0x00007f7d60661000)  $ ghc foo.hs $ ldd foo     linux-vdso.so.1 =>  (0x00007fff2d3ff000)     libgmp.so.10 => /usr/lib/libgmp.so.10 (0x00007f50014ec000)     libm.so.6 => /lib/libm.so.6 (0x00007f5001269000)     librt.so.1 => /lib/librt.so.1 (0x00007f5001061000)     libdl.so.2 => /lib/libdl.so.2 (0x00007f5000e5d000)     libc.so.6 => /lib/libc.so.6 (0x00007f5000afc000)     libpthread.so.0 => /lib/libpthread.so.0 (0x00007f50008df000)     /lib/ld-linux-x86-64.so.2 (0x00007f5001759000) 

If I try to compile it with(without '-dynamic'):

$ ghc --make -shared -fPIC foo.hs -o libfoo.so Linking libfoo.so ... /usr/bin/ld: foo.o: relocation R_X86_64_32S against `stg_CAF_BLACKHOLE_info' can not be used when making a shared object; recompile with -fPIC foo.o: could not read symbols: Bad value collect2: ld returned 1 exit status 

When googling I found something about this whole issue - that it may come from the fact that GHC is compiled in a specific way(dynamic/static?) and so static linking is not possible. If this is true how is it possible that the ELF binary is statically linked?

Anyway, I am hoping someone can shed some light on this since a huge amount of googling left me with more questions than I started with.

Huge thanks.

like image 755
kuratkull Avatar asked Feb 27 '11 03:02

kuratkull


1 Answers

The canonical way of is this:

  1. Export the functions (via FFI) to initialise RTS (runtime system) by the foreign program
  2. Export actual functions you would like to implement in Haskell

The following sections of manual describe this: [1] [2]

On the other way, you can try technique described in this blog post (which mine, by the way):

http://mostlycode.wordpress.com/2010/01/03/shared-haskell-so-library-with-ghc-6-10-4-and-cabal/

It boils down to creating a small C file which is called automatically right after a library is loaded. It should be linked together into the library.

#define CAT(a,b) XCAT(a,b) #define XCAT(a,b) a ## b #define STR(a) XSTR(a) #define XSTR(a) #a  #include  extern void CAT (__stginit_, MODULE) (void);  static void library_init (void) __attribute__ ((constructor)); static void library_init (void) {       /* This seems to be a no-op, but it makes the GHCRTS envvar work. */       static char *argv[] = { STR (MODULE) ".so", 0 }, **argv_ = argv;       static int argc = 1;        hs_init (&argc, &argv_);       hs_add_root (CAT (__stginit_, MODULE)); }  static void library_exit (void) __attribute__ ((destructor)); static void library_exit (void) {     hs_exit (); } 

Edit: Original blog post describing this technique is this: http://weblog.haskell.cz/pivnik/building-a-shared-library-in-haskell/

like image 73
Tener Avatar answered Oct 04 '22 14:10

Tener