开发者

How to compile Haskell to a static library?

开发者 https://www.devze.com 2023-02-13 12:25 出处:网络
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

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 th开发者_开发百科e 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.


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/


This makes ghc compile statically (note that the pthread is before optl-static): ghc --make -static -optl-pthread -optl-static test.hs

Edit: But the static compilation seems to be a bit risky. Most of the times there are some errors. And on my x64 fedora it doesn't work at all. The resulting binary is also quite large, 1.5M for main = putStrLn "hello world"

0

精彩评论

暂无评论...
验证码 换一张
取 消