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 symbolen hFoo 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


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow