¿Cómo compilar Haskell a una biblioteca estática?


Hey, Estoy aprendiendo Haskell y estoy interesado en usarlo para hacer bibliotecas estáticas para usar en Python y probablemente en C. Después de buscar en Google descubrí cómo hacer que GHC genere un objeto compartido, pero depende dinámicamente de las bibliotecas de GHC. El ELF resultante de compilar en GHC es dinámicamente dependiente y solo en C libs y está un poco por debajo de un MB de tamaño - se ha vinculado estáticamente con las libs de GHC. ¿Cómo y si se puede lograr esto para objetos compartidos?

Ejemplo de corriente estado:

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

Si intento compilarlo con (sin '-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

Cuando busqué en Google encontré algo sobre todo este asunto - que puede provenir del hecho de que GHC está compilado de una manera específica (¿dinámica/estática?) y por lo tanto la vinculación estática no es posible. Si esto es cierto, ¿cómo es posible que el binario ELF esté enlazado estáticamente?

De todos modos, espero que alguien pueda arrojar algo de luz sobre esto ya que una gran cantidad de googleo me dejó con más preguntas de las que empecé con.

Muchas gracias.

Author: kuratkull, 2011-02-27

2 answers

El camino canónico de es este:

  1. Exportar las funciones (vía FFI) para inicializar RTS (runtime system) por el programa extranjero
  2. Exportar las funciones reales que le gustaría implementar en Haskell

Las siguientes secciones del manual se describen en este: [1] [2]

Por otro lado, puede probar la técnica descrita en este post del blog (que la mía, por el way):

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

Se reduce a crear un pequeño archivo C que se llama automáticamente justo después de cargar una biblioteca. Debe estar vinculado a la biblioteca.

#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 ();
}

Editar: Entrada original del blog que describe esta técnica es esta: 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-19 17:45:29

Esto hace que ghc compile estáticamente (tenga en cuenta que el pthread está antes de optl-static): ghc --make -static -optl-pthread -optl-static test.hs

Editar: Pero la compilación estática parece ser un poco arriesgada. La mayoría de las veces hay algunos errores. Y en mi fedora x64 no funciona en absoluto. El binario resultante también es bastante grande, 1,5 M para 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-27 21:20:09