Buscar..


Sintaxis

  • importación extranjera ccall inseguro "foo" hFoo :: Int32 -> IO Int32 {- Importa una función llamada foo en algún archivo de objeto, y define el símbolo hFoo que se puede llamar con el código de Haskell. -}

Observaciones

Si bien cabal tiene soporte para incluir bibliotecas de C y C ++ en un paquete de Haskell, hay algunos errores. Primero, si tiene datos (en lugar de una función) definidos en bo que se usan en ao , y liste las C-sources: ac, bc , entonces Cabal no podrá encontrar los datos. Esto está documentado en # 12152 . Una solución alternativa al utilizar cabal es reordenar la lista de C-sources C-sources: bc, ac para que sean C-sources: bc, ac . Es posible que esto no funcione cuando se usa la pila, porque la pila siempre vincula las C-sources alfabéticamente, independientemente del orden en el que se enumeran.

Otro problema es que debe rodear cualquier código C ++ en los archivos de encabezado (.h) con guardias #ifdef __cplusplus . Esto se debe a que GHC no entiende el código C ++ en los archivos de encabezado. Aún puede escribir código C ++ en archivos de encabezado, pero debe rodearlo con guardas.

ccall refiere a la convención de llamada ; actualmente se ccall y stdcall (convención de Pascal). La palabra clave unsafe es opcional; esto reduce la sobrecarga para funciones simples, pero puede causar interbloqueos si la función foránea se bloquea indefinidamente o no tiene suficiente permiso para ejecutar 1 .

Llamando C desde Haskell

Por razones de rendimiento, o debido a la existencia de bibliotecas C maduras, es posible que desee llamar al código C desde un programa de Haskell. Este es un ejemplo simple de cómo puede pasar datos a una biblioteca de C y obtener una respuesta.

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 palabra clave unsafe genera una llamada más eficiente que "segura", pero requiere que el código C nunca realice una devolución de llamada al sistema Haskell. Ya que foo está completamente en C y nunca llamará a Haskell, podemos usar unsafe .

También necesitamos dar instrucciones a Cabal para compilar y enlazar en C fuente.

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

Entonces puedes correr:

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

Pasar funciones de Haskell como devoluciones de llamada a código C.

Es muy común que las funciones C acepten punteros a otras funciones como argumentos. El ejemplo más popular es configurar una acción para que se ejecute cuando se hace clic en un botón en alguna biblioteca de herramientas de GUI. Es posible pasar las funciones de Haskell como C callbacks.

Para llamar a esta función C:

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

Primero lo importamos al código de Haskell:

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

Ahora, observando cómo se define Object_Event_Cb en el encabezado C, defina qué Callback está en Haskell:

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

Finalmente, cree una función especial que envuelva la función Haskell de tipo Callback en un puntero FunPtr Callback :

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

Ahora podemos registrar el callback con código C:

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

Es importante liberar FunPtr asignado una vez que FunPtr registro de la devolución de llamada:

freeHaskellFunPtr cbPtr


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow