Jak skompilować Haskell do statycznej biblioteki?

Hej, Uczę się Haskella i jestem zainteresowany używaniem go do tworzenia bibliotek statycznych do używania w Pythonie i prawdopodobnie C. Po googlowaniu dowiedziałem się, jak zmusić GHC do wyprowadzenia współdzielonego obiektu, ale to Dynamicznie zależy od bibliotek GHC. Wynikający z kompilacji w GHC ELF jest zależny dynamicznie tylko od bibliotek C i jest nieco poniżej rozmiaru MB - został statycznie połączony z bibliotekami GHC. Jak i czy można to osiągnąć dla obiektów współdzielonych?

Przykład prądu Państwo:

$ 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)

Jeśli spróbuję skompilować go z (bez '- 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

Podczas googlowania znalazłem coś o tej całej sprawie - że może to wynikać z faktu, że GHC jest kompilowany w specyficzny sposób (dynamiczny/statyczny?), a więc statyczne linkowanie nie jest możliwe. Jeśli to prawda, jak to możliwe, że binarny ELF jest statycznie połączony?

W każdym razie, mam nadzieję, że ktoś może rzucić trochę światła na ten temat, ponieważ ogromna ilość googlowania pozostawiła mnie więcej pytań niż zacząłem z.

Wielkie dzięki.
Author: kuratkull, 2011-02-27

2 answers

Kanoniczny sposób jest taki:

  1. eksport funkcji (poprzez FFI) do inicjalizacji RTS (runtime system) przez zagraniczny program
  2. Eksportuj rzeczywiste funkcje, które chcesz zaimplementować w Haskell

Następujące sekcje podręcznika opisują to: [1] [2]

W drugą stronę można spróbować techniki opisanej w tym wpisie na blogu (który Mój, przez sposób): {]}

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

Sprowadza się to do utworzenia małego pliku C, który jest wywoływany automatycznie zaraz po załadowaniu biblioteki. Powinno być połączone razem z biblioteką.

#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: oryginalny wpis na blogu opisujący tę technikę jest taki: http://weblog.haskell.cz/pivnik/building-a-shared-library-in-haskell/

 4
Author: Tener,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-19 17:45:29

To sprawia, że ghc kompiluje się statycznie (zauważ, że pthread jest przed optl-static): ghc --make -static -optl-pthread -optl-static test.hs

Edit: ale statyczna kompilacja wydaje się być nieco ryzykowna. W większości przypadków zdarzają się błędy. A na mojej Fedorze x64 to w ogóle nie działa. Wynik binarny jest również dość duży, 1,5 M dla main = putStrLn "hello world"

 0
Author: Masse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-27 21:20:09