Haskell Language
Fremdfunktionsschnittstelle
Suche…
Syntax
- fremder import ccall unsicher "foo" hFoo :: Int32 -> IO Int32 {- Importiert eine Funktion namens
fooin eine Objektdatei und definiert das SymbolhFoodas 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