2011-02-27 18 views
26

Oye, Estoy aprendiendo Haskell y estoy interesado en usarlo para hacer bibliotecas estáticas para usar en Python y probablemente C. Después de buscar en Google descubrí cómo hacer que GHC produzca un objeto compartido, pero depende dinámicamente en las bibliotecas de GHC. El ELF resultante de la compilación en GHC depende dinámicamente y solo en C libs y tiene un tamaño algo menor que MB, se ha vinculado estáticamente con las librerías de GHC. ¿Cómo y si se puede lograr esto para los objetos compartidos?¿Cómo compilar Haskell a una biblioteca estática?

Ejemplo del estado actual:

$ 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 compilar con (y 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 google he encontrado algo acerca de toda esta cuestión - que puede provenir del hecho de que GHC se compila de una manera específica (dinámica/estática?) y por lo tanto no es posible establecer enlaces estáticos. Si esto es cierto, ¿cómo es posible que el binario ELF esté vinculado estáticamente?

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

Muchísimas gracias.

+0

qué sistema utiliza? Parece que es x86_64 Linux. La versión de GHC también es importante, ya que podría ser un error que se haya solucionado desde entonces. La vinculación dinámica ha tenido algunos errores en el pasado y podría ser uno de ellos. – Tener

+0

@Tener | Compilador Haskell de Glasgow, Versión 6.12.3, para Haskell 98, etapa 2 arrancada por GHC versión 6.12.1 | Tal vez debería probar GHC 7 para ver si tiene este problema cubierto. – kuratkull

+0

@Tener.Llegué a la instalación de GHC7, y todavía no está funcionando, aunque me está dando un error un poco diferente. = >>> '-> ghc --make -shared -fPIC bwt.hs -o libbwt.so [1 of 1] Compilación principal (bwt.hs, bwt.o) Enlazando libbwt.so .. /usr/bin/ld: /usr/lib/ghc-7.0.2/base-4.3.1.0/libHSbase-4.3.1.0.a(Base__90.o): la reubicación R_X86_64_32S contra "stg_upd_frame_info" no se puede usar cuando hacer un objeto compartido; recompile con -fPIC /usr/lib/ghc-7.0.2/base-4.3.1.0/libHSbase-4.3.1.0.a: no se pudieron leer símbolos: valor incorrecto collect2: ld devuelto 1 estado de salida ' – kuratkull

Respuesta

4

La forma canónica de es la siguiente:

  1. exportación las funciones (a través de FFI) para inicializar RTS (sistema de tiempo de ejecución) por el programa extranjero
  2. exportación funciones reales que le gustaría implementar en Haskell

Las siguientes secciones de este manual describen: [1][2]

Por otro lado, se puede tratar técnica descrita en esta entrada del blog (que la mía, por cierto):

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

Se reduce a la creación de un pequeño archivo C que se llama automáticamente justo después de una la biblioteca está cargada Debe estar vinculado en 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(); 
} 

Edición: Original entrada de blog que describe esta técnica es la siguiente: http://weblog.haskell.cz/pivnik/building-a-shared-library-in-haskell/

+3

Gracias, pero ninguno de estos métodos funciona (los mismos errores) y probablemente se deba a esto (se encuentra en uno de los enlaces que proporcionó): "Sin embargo, en la mayoría de las plataformas eso requeriría que todas las bibliotecas estáticas se hayan construido con -fPIC que el código es adecuado para incluirlo en una biblioteca compartida y no lo hacemos en este momento ". Puedo asumir que tendría que volver a compilar GHC con -fPIC manualmente para resolver mi problema, de lo contrario, simplemente no es posible. Marcaré su respuesta como una respuesta correcta, ya que todo esto _debe_ funcionar después de recompilar GHC. Muchas gracias :) – kuratkull

0

Esto hace GHC compilan estáticamente (tenga en cuenta que el pthread es antes OPTL-estática): ghc --make -static -optl-pthread -optl-static test.hs

Editar: Pero la compilación estática parece ser un poco arriesgado. La mayoría de las veces hay algunos errores. Y en mi x64 fedora no funciona en absoluto. El binario resultante también es bastante grande, 1,5 M para main = putStrLn "hello world"

+5

Pero esto hace que los ejecutables sean estáticos, quiero tener bibliotecas estáticas (*. So/*. A). Intenté usar el indicador '-shared' pero obtuve: /usr/bin/ld: /usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.2/crtbeginT.o: relocation R_X86_64_32 contra '__DTOR_END__ 'no se puede usar cuando se crea un objeto compartido; recompile con -fPIC /usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.2/crtbeginT.o: could not read symbols: Bad value. Parece que hacer bibliotecas estáticas puede no ser tan fácil después de todo. ¿O estoy haciendo algo mal? – kuratkull

Cuestiones relacionadas