Ricerca…


Sintassi

  • importazione straniera ccall non sicuro "foo" hFoo :: Int32 -> IO Int32 {- Importa una funzione denominata foo in un file oggetto e definisce il simbolo hFoo che può essere chiamato con il codice Haskell. -}

Osservazioni

Mentre la cabal ha il supporto per includere le librerie C e C ++ in un pacchetto Haskell, ci sono alcuni bug. Innanzitutto, se si dispone di dati (piuttosto che di una funzione) definiti in bo che sono utilizzati in ao , ed elenca i C-sources: ac, bc , quindi cabal non sarà in grado di trovare i dati. Questo è documentato in # 12152 . Una soluzione utilizzando cricca è quello di riordinare le C-sources elenco da C-sources: bc, ac . Questo potrebbe non funzionare quando si usa lo stack, perché lo stack collega sempre le C-sources ordine alfabetico, indipendentemente dall'ordine in cui vengono elencate.

Un altro problema è che è necessario circondare qualsiasi codice C ++ nei file di intestazione (.h) con le protezioni #ifdef __cplusplus . Questo perché GHC non capisce il codice C ++ nei file di intestazione. Puoi ancora scrivere codice C ++ nei file di intestazione, ma devi circondarlo di guardie.

ccall riferisce alla convenzione di chiamata ; attualmente sono supportati ccall e stdcall (convenzione Pascal). La parola chiave unsafe è facoltativa; questo riduce il sovraccarico per le funzioni semplici ma può causare deadlock se i blocchi di funzioni estranei indefinitamente o non dispone dell'autorizzazione sufficiente per l'esecuzione 1 .

Chiamando C da Haskell

Per motivi di prestazioni, o per l'esistenza di librerie C mature, potresti voler chiamare il codice C da un programma Haskell. Ecco un semplice esempio di come è possibile passare i dati a una libreria C e ottenere una risposta indietro.

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

La parola chiave unsafe genera una chiamata più efficiente di "sicuro", ma richiede che il codice C non effettui mai una chiamata al sistema Haskell. Dato che foo è completamente in C e non chiamerà mai Haskell, possiamo usare unsafe .

Abbiamo anche bisogno di istruire la cabala per compilare e collegare in C source.

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

Quindi puoi eseguire:

> cabal configure
> cabal build foo
> ./dist/build/foo/foo
42

Passare Haskell funziona come richiamata al codice C.

È molto comune che le funzioni C accettino i puntatori ad altre funzioni come argomenti. L'esempio più popolare è l'impostazione di un'azione da eseguire quando si fa clic su un pulsante in una libreria di toolkit GUI. È possibile passare le funzioni Haskell come callback C.

Per chiamare questa funzione C:

void event_callback_add (Object *obj, Object_Event_Cb func, const void *data)

per prima cosa lo importiamo nel codice Haskell:

foreign import ccall "header.h event_callback_add"
    callbackAdd :: Ptr () -> FunPtr Callback -> Ptr () -> IO ()

Ora, osservando come Object_Event_Cb è definito nell'intestazione C, definisci quale Callback trova in Haskell:

type Callback = Ptr () -> Ptr () -> IO ()

Infine, crea una funzione speciale che FunPtr Callback funzione Haskell di tipo Callback in un puntatore FunPtr Callback :

foreign import ccall "wrapper"
    mkCallback :: Callback -> IO (FunPtr Callback)

Ora possiamo registrare il callback con il codice C:

cbPtr <- mkCallback $ \objPtr dataPtr -> do
    -- callback code
    return ()
callbackAdd cpPtr

È importante liberare FunPtr assegnato dopo aver annullato la registrazione della richiamata:

freeHaskellFunPtr cbPtr


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow