2010-12-11 13 views
4

Ich habe gedacht, dass es schön wäre Midori Plugins mit Haskell zu erstellen, aber es scheint fast unmöglich zu sein. Das Problem liegt beim Exportieren von Haskell-Funktionen durch FFI, da der GhC-Compiler eine große Anzahl von -u-Schaltern verwendet.Interfacing haskell mit c

tHat jemand Haskell in einem ähnlichen Kontext verwendet worden, ohne gcc für ghc ersetzen zu müssen? Wenn ja, wie ist es gelaufen und welche Reifen haben sie durchlaufen?

Edit: Einige Beispiele angefordert wurden, so hier:

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

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

mit ghc --make -no-hs-main export.hs test.c Kompilieren erstellt eine a.out ausführbare Datei, die funktioniert. Die ghc verwendet den folgenden Befehl für die Verknüpfung:

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

die -u Schalter aus- (Abfahrt nur -l, -L und einige zusätzliche Flags) von der vorherige Befehl kompilieren und kehrt nicht (und einige 50 oder so mehr Linien)

/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

Dies ist wahrscheinlich der zugehörige Teil des Handbuchs: http://www.haskell.org/ghc/docs/latest/html/users_guide/ffi-ghc.html Siehe insbesondere 8.2.1.2. Sie können eine Bibliothek erstellen, die in Haskell geschrieben ist und über C-Code aufgerufen werden kann. Dann musst du nur einen Klebecode in C schreiben, um in ein Plugin oder was auch immer zu verwandeln. Aber ich habe es nicht selbst gemacht, bitte warten Sie, bis erfahrene Benutzer von "Auslandsexport" antworten. – sastanin

+1

@Jetxee, ist dir bewusst, dass das Schreiben einer Antwort als Kommentar es dem OP verbietet, es zu akzeptieren? :) – Kos

+0

Ja, Sie haben Recht, aber wenn Sie versuchen, diese Objekte zu verknüpfen, werden undefinierte Fehler, die mit -u-Schalter behoben werden können, aber es gibt viele von ihnen, und ich _think_ sie könnten von Programm zu Programm wechseln – Masse

Antwort

2

Ich konnte das Problem lösen.

Ich verwende die folgenden Dateien:

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

Ich bin Kompilieren die Bibliothek mit 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 und die ausführbare Datei mit gcc -c main.c -I/usr/lib/ghc-6.12.1/include -L. -ltest -Wl,-rpath=$PWD

Der wichtige Teil der Bibliothek geteilt und mit der rts Bibliothek macht auch verbunden, die nicht standardmäßig kommt. Der rpath macht es so, dass ohne LD_LIBRARY_PATH ausgeführt werden kann.

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

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

1

Dies ist wahrscheinlich der zugehörige Teil des Handbuchs:

8.2. Using the FFI with GHC

Siehe insbesondere 8.2.1.2. Sie können eine Bibliothek erstellen, die in Haskell geschrieben ist und über C-Code aufgerufen werden kann. Dann musst du nur einen Klebecode in C schreiben, um in ein Plugin oder was auch immer zu verwandeln. Aber ich habe es nicht selbst gemacht, bitte warten Sie auf erfahrene Benutzer von foreign export zu beantworten.