Recherche…


Syntaxe

  • import étranger ccall unsafe "foo" hFoo :: Int32 -> IO Int32 {- Importe une fonction nommée foo dans un fichier objet et définit le symbole hFoo qui peut être appelé avec le code Haskell. -}

Remarques

Bien que cabal prenne en charge l'inclusion de bibliothèques C et C ++ dans un package Haskell, il existe quelques bogues. D'abord, si vous avez des données (plutôt qu'une fonction) définies dans bo qui sont utilisées dans ao , et répertoriez les C-sources: ac, bc , alors cabal ne pourra pas trouver les données. Ceci est documenté dans # 12152 . Une solution de contournement lors de l'utilisation de cabal est de réorganiser la liste de C-sources C-sources: bc, ac pour qu'elle soit C-sources: bc, ac . Cela peut ne pas fonctionner lorsque vous utilisez la pile, car la pile lie toujours les C-sources ordre alphabétique, quel que soit l'ordre dans lequel vous les répertoriez.

Un autre problème est que vous devez entourer tout code C ++ dans les fichiers d'en-tête (.h) avec les gardes #ifdef __cplusplus . C'est parce que GHC ne comprend pas le code C ++ dans les fichiers d'en-tête. Vous pouvez toujours écrire du code C ++ dans les fichiers d'en-tête, mais vous devez l'entourer de gardes.

ccall fait référence à la convention d'appel ; actuellement ccall et stdcall (convention Pascal) sont supportés. Le mot clé unsafe est facultatif; Cela réduit la surcharge pour les fonctions simples, mais peut provoquer des blocages si la fonction étrangère bloque indéfiniment ou si les autorisations d'exécution sont insuffisantes 1 .

Appeler C de Haskell

Pour des raisons de performances, ou en raison de l'existence de bibliothèques C matures, vous souhaiterez peut-être appeler du code C à partir d'un programme Haskell. Voici un exemple simple de la façon dont vous pouvez transmettre des données à une bibliothèque C et obtenir une réponse.

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

Le mot-clé unsafe génère un appel plus efficace que 'safe', mais requiert que le code C ne rappelle jamais le système Haskell. Puisque foo est complètement en C et n'appellera jamais Haskell, nous pouvons utiliser unsafe .

Nous devons également demander à cabal de compiler et de lier le code source C.

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

Ensuite, vous pouvez exécuter:

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

Passer Haskell fonctionne comme des rappels au code C.

Il est très courant que les fonctions C acceptent des pointeurs vers d'autres fonctions en tant qu'arguments. L'exemple le plus courant consiste à définir une action à exécuter lorsqu'un bouton est cliqué dans une bibliothèque de toolkit GUI. Il est possible de passer des fonctions Haskell en tant que rappels C.

Pour appeler cette fonction C:

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

nous l'importons d'abord dans le code Haskell:

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

Maintenant, en regardant comment Object_Event_Cb est défini dans l'en-tête C, définissez ce que Callback est dans Haskell:

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

Enfin, créez une fonction spéciale qui FunPtr Callback fonction Haskell de type Callback dans un pointeur FunPtr Callback :

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

Maintenant, nous pouvons enregistrer le rappel avec le code C:

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

Il est important de libérer FunPtr alloué une fois que vous FunPtr le rappel:

freeHaskellFunPtr cbPtr


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow