Haskell Language
Fremdfunktionsschnittstelle
Suche…
Syntax
- fremder import ccall unsicher "foo" hFoo :: Int32 -> IO Int32 {- Importiert eine Funktion namens
foo
in eine Objektdatei und definiert das SymbolhFoo
das mit Haskell-Code aufgerufen werden kann. -}
Bemerkungen
Cabal unterstützt zwar das Einbinden von C- und C ++ - Bibliotheken in ein Haskell-Paket, es gibt jedoch einige Fehler. Erstens, wenn Sie in bo
definierte Daten (und nicht eine Funktion) haben, die in ao
, und die C-sources: ac, bc
, dann kann cabal die Daten nicht finden. Dies ist in # 12152 dokumentiert. Eine Problemumgehung bei Verwendung von Kabal besteht darin, die Liste der C-sources
in C-sources: bc, ac
. Dies funktioniert möglicherweise nicht, wenn Stack verwendet wird, da Stack die C-sources
alphabetisch verknüpft, unabhängig von der Reihenfolge, in der Sie sie auflisten.
Ein #ifdef __cplusplus
ist, dass Sie jeden C ++ - Code in Header-Dateien (.h) mit #ifdef __cplusplus
Guards umgeben müssen. Dies liegt daran, dass GHC C ++ - Code in Header-Dateien nicht versteht. Sie können weiterhin C ++ - Code in Header-Dateien schreiben, aber Sie müssen ihn mit Wachen umgeben.
ccall
bezieht sich auf die aufrufende Konvention ; derzeit werden ccall
und stdcall
(Pascal-Konvention) unterstützt. Das unsafe
Schlüsselwort ist optional. dies reduziert für einfache Funktionen Overhead , sondern kann Deadlocks verursachen , wenn die Fremdfunktionsblöcke auf unbestimmte Zeit oder unzureichende Berechtigung hat , auszuführen 1 .
C aus Haskell anrufen
Aus Leistungsgründen oder wegen des Vorhandenseins ausgereifter C-Bibliotheken möchten Sie möglicherweise C-Code aus einem Haskell-Programm aufrufen. Hier ein einfaches Beispiel, wie Sie Daten an eine C-Bibliothek übergeben und eine Antwort erhalten können.
foo.c:
#include <inttypes.h>
int32_t foo(int32_t a) {
return a+1;
}
Foo.hs:
import Data.Int
main :: IO ()
main = print =<< hFoo 41
foreign import ccall unsafe "foo" hFoo :: Int32 -> IO Int32
Das unsafe
Schlüsselwort erzeugt einen effizienteren Aufruf als 'safe', setzt jedoch voraus, dass der C-Code niemals einen Rückruf an das Haskell-System ausführt. Da foo
vollständig in C ist und Haskell niemals anrufen wird, können wir unsafe
.
Wir müssen Kabal außerdem anweisen, in C-Quelle zu kompilieren und zu verknüpfen.
foo.cabal:
name: foo
version: 0.0.0.1
build-type: Simple
extra-source-files: *.c
cabal-version: >= 1.10
executable foo
default-language: Haskell2010
main-is: Foo.hs
C-sources: foo.c
build-depends: base
Dann kannst du laufen:
> cabal configure
> cabal build foo
> ./dist/build/foo/foo
42
Übergeben von Haskell-Funktionen als Rückrufe an C-Code.
Es ist üblich, dass C-Funktionen Zeiger auf andere Funktionen als Argumente akzeptieren. Das bekannteste Beispiel ist das Festlegen einer Aktion, die ausgeführt wird, wenn eine Schaltfläche in einer GUI-Toolkit-Bibliothek angeklickt wird. Haskell-Funktionen können als C-Callbacks übergeben werden.
So rufen Sie diese C-Funktion auf:
void event_callback_add (Object *obj, Object_Event_Cb func, const void *data)
Wir importieren es zuerst in den Haskell-Code:
foreign import ccall "header.h event_callback_add"
callbackAdd :: Ptr () -> FunPtr Callback -> Ptr () -> IO ()
Object_Event_Cb
nun betrachten, wie Object_Event_Cb
im C-Header definiert ist, definieren Sie, was Callback
in Haskell ist:
type Callback = Ptr () -> Ptr () -> IO ()
Erstellen Sie schließlich eine spezielle Funktion, die die Haskell-Funktion vom Typ Callback
in einen Zeiger FunPtr Callback
:
foreign import ccall "wrapper"
mkCallback :: Callback -> IO (FunPtr Callback)
Jetzt können wir einen Rückruf mit C-Code registrieren:
cbPtr <- mkCallback $ \objPtr dataPtr -> do
-- callback code
return ()
callbackAdd cpPtr
Es ist wichtig, FunPtr
Sie den zugewiesenen FunPtr
sobald Sie den Rückruf FunPtr
:
freeHaskellFunPtr cbPtr