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.2 answers
Kanoniczny sposób jest taki:
- eksport funkcji (poprzez FFI) do inicjalizacji RTS (runtime system) przez zagraniczny program
- 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/
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"
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