Haskell Language
Gränssnitt för utländsk funktion
Sök…
Syntax
- utländsk import ccall osäker "foo" hFoo :: Int32 -> IO Int32 {- Importerar en funktion som heter
foo
i någon objektfil och definierar symbolenhFoo
som kan kallas med Haskell-kod. -}
Anmärkningar
Medan cabal har stöd för att inkludera ett C- och C ++ -bibliotek i ett Haskell-paket, finns det några buggar. Först, om du har data (snarare än en funktion) definierade i bo
som används i ao
, och listar C-sources: ac, bc
, kommer cabal inte att kunna hitta data. Detta är dokumenterat i # 12152 . En lösning när du använder kabal är att ordna C-sources
till C-sources: bc, ac
. Detta kanske inte fungerar när du använder stack, eftersom stack alltid länkar C-sources
alfabetiskt, oavsett i vilken ordning du listar dem.
Ett annat problem är att du måste omge alla C ++ #ifdef __cplusplus
(.h) med #ifdef __cplusplus
. Detta beror på att GHC inte förstår C ++ -kod i sidfiler. Du kan fortfarande skriva C ++ -kod i rubrikfiler, men du måste omge den med vakter.
ccall
hänvisar till den anropande konvention; för närvarande ccall
och stdcall
(Pascal-konvention). Det unsafe
nyckelordet är valfritt; detta minskar omkostnaderna för enkla funktioner men kan orsaka dödlås om den främmande funktionen blockerar på obestämd tid eller har otillräckligt tillstånd att utföra 1 .
Ringer C från Haskell
Av prestationsskäl, eller på grund av att det finns mogna C-bibliotek, kanske du vill ringa C-kod från ett Haskell-program. Här är ett enkelt exempel på hur du kan skicka data till ett C-bibliotek och få svar tillbaka.
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
Det unsafe
nyckelordet genererar ett mer effektivt samtal än "säkert", men kräver att C-koden aldrig gör ett återuppringning till Haskell-systemet. Eftersom foo
är helt i C och aldrig kommer att ringa Haskell, kan vi använda unsafe
.
Vi måste också instruera cabal att sammanställa och länka i C-källa.
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
Då kan du springa:
> cabal configure
> cabal build foo
> ./dist/build/foo/foo
42
Att skicka Haskell fungerar som återuppringningar till C-kod.
Det är mycket vanligt att C-funktioner accepterar pekare till andra funktioner som argument. Det mest populära exemplet är att ställa in en åtgärd som ska utföras när man klickar på en knapp i ett GUI-verktygssatsbibliotek. Det är möjligt att passera Haskell-funktioner som C-återuppringningar.
För att kalla denna C-funktion:
void event_callback_add (Object *obj, Object_Event_Cb func, const void *data)
vi importerar den först till Haskell-kod:
foreign import ccall "header.h event_callback_add"
callbackAdd :: Ptr () -> FunPtr Callback -> Ptr () -> IO ()
Nu ska du titta på hur Object_Event_Cb
definieras i C-huvud, definiera vad som är Callback
i Haskell:
type Callback = Ptr () -> Ptr () -> IO ()
Slutligen, skapa en speciell funktion som skulle linda in Haskell-funktion av typen Callback
i en pekare FunPtr Callback
:
foreign import ccall "wrapper"
mkCallback :: Callback -> IO (FunPtr Callback)
Nu kan vi registrera återuppringning med C-kod:
cbPtr <- mkCallback $ \objPtr dataPtr -> do
-- callback code
return ()
callbackAdd cpPtr
Det är viktigt att gratis tilldelad FunPtr
när du avregistrerar återuppringningen:
freeHaskellFunPtr cbPtr