2010-12-11 29 views
4

Je pensais que ce serait sympa de créer des plugins midori avec haskell, mais il semble presque impossible. Le problème réside dans l'exportation de fonctions haskell via ffi, car le compilateur ghc utilise une quantité massive de commutateurs -u.Interfaçage haskell avec c

t Quelqu'un a-t-il déjà été utilisé dans un contexte similaire, sans avoir à remplacer gcc par ghc? Si oui, comment cela s'est-il passé et quels cerceaux sont-ils passés?

Edit: Quelques exemples ont été demandés, alors voici:

export.hs

{-# LANGUAGE ForeignFunctionInterface #-} 
module Export where 
import Foreign.C 
import Foreign.C.Types 

foo :: IO Int 
foo = return 2 

foreign export ccall foo :: IO Int 

test.c (ifdefs ciselée)

#include <stdio.h> 
#include "HsFFI.h" 
#include "export_stub.h" 

extern void __stginit_Export(void); 

int main(int argc, char **argv) 
{ 
    int i; 
    hs_init(&argc, &argv); 
    hs_add_root(__stginit_Export); 
    i = foo(); 
    printf("%d\n", i); 
    hs_exit(); 
    return 0; 
} 

avec ghc --make -no-hs-main export.hs test.c crée Compiler un a.out exécutable qui fonctionne. Le GHC utilise la commande suivante pour relier:

collect2 --build-id --eh-frame-hdr -m elf_i386 --hash-style=both -dynamic-linker /lib/ld-linux.so.2 -o a.out -z relro -u ghczmprim_GHCziTypes_Izh_static_info -u ghczmprim_GHCziTypes_Czh_static_info -u ghczmprim_GHCziTypes_Fzh_static_info -u ghczmprim_GHCziTypes_Dzh_static_info -u base_GHCziPtr_Ptr_static_info -u base_GHCziWord_Wzh_static_info -u base_GHCziInt_I8zh_static_info -u base_GHCziInt_I16zh_static_info -u base_GHCziInt_I32zh_static_info -u base_GHCziInt_I64zh_static_info -u base_GHCziWord_W8zh_static_info -u base_GHCziWord_W16zh_static_info -u base_GHCziWord_W32zh_static_info -u base_GHCziWord_W64zh_static_info -u base_GHCziStable_StablePtr_static_info -u ghczmprim_GHCziTypes_Izh_con_info -u ghczmprim_GHCziTypes_Czh_con_info -u ghczmprim_GHCziTypes_Fzh_con_info -u ghczmprim_GHCziTypes_Dzh_con_info -u base_GHCziPtr_Ptr_con_info -u base_GHCziPtr_FunPtr_con_info -u base_GHCziStable_StablePtr_con_info -u ghczmprim_GHCziBool_False_closure -u ghczmprim_GHCziBool_True_closure -u base_GHCziPack_unpackCString_closure -u base_GHCziIOziException_stackOverflow_closure -u base_GHCziIOziException_heapOverflow_closure -u base_ControlziExceptionziBase_nonTermination_closure -u base_GHCziIOziException_blockedIndefinitelyOnMVar_closure -u base_GHCziIOziException_blockedIndefinitelyOnSTM_closure -u base_ControlziExceptionziBase_nestedAtomically_closure -u base_GHCziWeak_runFinalizzerBatch_closure -u base_GHCziTopHandler_runIO_closure -u base_GHCziTopHandler_runNonIO_closure -u base_GHCziConc_ensureIOManagerIsRunning_closure -u base_GHCziConc_runSparks_closure -u base_GHCziConc_runHandlers_closure /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crt1.o /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crti.o /usr/lib/gcc/i486-linux-gnu/4.4.3/crtbegin.o -L/usr/lib/ghc-6.12.1/base-4.2.0.0 -L/usr/lib/ghc-6.12.1/integer-gmp-0.2.0.0 -L/usr/lib/ghc-6.12.1/ghc-prim-0.2.0.0 -L/usr/lib/ghc-6.12.1 -L/usr/lib/gcc/i486-linux-gnu/4.4.3 -L/usr/lib/gcc/i486-linux-gnu/4.4.3 -L/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/i486-linux-gnu/4.4.3/../../.. -L/usr/lib/i486-linux-gnu export.o export_stub.o test.o -lHSbase-4.2.0.0 -lHSinteger-gmp-0.2.0.0 -lgmp -lHSghc-prim-0.2.0.0 -lHSrts -lm -lffi -lrt -ldl -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i486-linux-gnu/4.4.3/crtend.o /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crtn.o

Retrait des commutateurs -u (en laissant juste -l, -L et quelques drapeaux supplémentaires) de la commande précédente ne compile pas et retourne (et quelque 50 ou si plus lignes)

/usr/lib/ghc-6.12.1/libHSrts.a(RtsAPI.o): In function `rts_mkFunPtr': 
(.text+0x5a9): undefined reference to `base_GHCziPtr_FunPtr_con_info' 
/usr/lib/ghc-6.12.1/libHSrts.a(RtsAPI.o): In function `rts_mkString': 
(.text+0x60f): undefined reference to `base_GHCziPack_unpackCString_closure' 
+4

Ceci est probablement la partie correspondante du manuel: http://www.haskell.org/ghc/docs/latest/html/users_guide/ffi-ghc.html Voir en particulier 8.2.1.2. Vous pouvez écrire une bibliothèque dans Haskell et l'appeler depuis le code C. Ensuite, il suffit d'écrire du code de collage en C pour le transformer en plugin ou autre. Mais je ne l'ai pas fait moi-même, veuillez attendre que les utilisateurs plus expérimentés de «l'exportation étrangère» répondent. – sastanin

+1

@Jetxee, savez-vous que l'écriture d'une réponse en commentaire interdit à l'OP de l'accepter? :) – Kos

+0

Oui, vous avez raison, mais en essayant de lier ces objets, causera des erreurs indéfinies, qui peuvent être corrigées avec les commutateurs -u, mais il y en a beaucoup, et je pense qu'ils pourraient changer de programme – Masse

Répondre

2

J'ai réussi à résoudre le problème.

J'utilise les fichiers suivants:

main.c

#include <stdio.h> 
#include "lib_stub.h" 
int main(int argc, char **argv) 
{ 
    puts("foo"); 
    printf("%d\n", hsfun(5)); 
    return 0; 
} 

lib.hs

{-# LANGUAGE ForeignFunctionInterface #-} 
module Test where 
import Foreign.C.Types 

hsfun :: CInt -> IO CInt 
hsfun x = do 
    putStrLn "Hello from haskell" 
    return (42 * x) 

foreign export ccall hsfun :: CInt -> IO CInt 

module_init.c

#include <HsFFI.h> 
extern void __stginit_Test(void); 

static void library_init(void) __attribute__((constructor)); 
static void library_init(void) 
{ 
    static char *argv[] = { "libtest.so", 0 }, **argv_ = argv; 
    static int argc = 1; 

    hs_init(&argc, &argv_); 
    hs_add_root(__stginit_Test); 
} 

static void library_exit(void) __attribute__((destructor)); 
static void library_exit(void) 
{ 
    hs_exit(); 
} 

Je compile la bibliothèque avec ghc --make -shared -dynamic -fPIC -o libtest.so lib.hs module_init.c -lHSrts-ghc6.12.1 -optl-Wl,-rpath,/usr/lib/ghc-6.12.1/ -L/usr/lib/ghc-6.12.1 et l'exécutable avec gcc -c main.c -I/usr/lib/ghc-6.12.1/include -L. -ltest -Wl,-rpath=$PWD

La partie importante est de la bibliothèque partagée et ayant la bibliothèque rts liée aussi qui ne vient pas par défaut. Le rpath fait en sorte qu'il puisse être exécuté sans LD_LIBRARY_PATH.

http://weblog.haskell.cz/pivnik/building-a-shared-library-in-haskell/

http://www.well-typed.com/blog/30

1

Ceci est probablement la partie correspondante du manuel:

8.2. Using the FFI with GHC

Voir en particulier 8.2.1.2. Vous pouvez écrire une bibliothèque dans Haskell et l'appeler depuis le code C. Ensuite, il suffit d'écrire du code de collage en C pour le transformer en plugin ou autre. Mais je ne l'ai pas fait moi-même, veuillez attendre les utilisateurs plus expérimentés de foreign export pour répondre.