Haskell: Comment obtenir les valeurs des constantes # define-d?
Question
Dans un programme Haskell, quelle est la meilleure façon d'utiliser les constantes définies dans les en-têtes C?
La solution
Pour cette tâche, hsc2hs est votre ami.
Pour un exemple simple, obtenons la valeur de INT_MAX
à limits.h
.
$ cat >IntMax.hsc
module Main where
#include <limits.h>
c_INT_MAX = #const INT_MAX
main = print c_INT_MAX
Avec hsc2hs, nous pouvons utiliser les en-têtes #include
et utiliser les valeurs des constantes avec la directive #const
.
Au lieu de construire à la main, utilisez Cabal:
$ cat >intmax.cabal
Name: intmax
Version: 0.0
Cabal-Version: >=1.2
Build-Type: Simple
Executable intmax
Main-Is: IntMax.hs
Build-Depends: base
Notez que même si le nom du programme principal est IntMax.hsc
, la ligne Main-Is
pointe sur IntMax.hs
. Lorsque Cabal recherche IntMax.hs
mais trouve IntMax.hsc
, il alimente automatiquement ce dernier via hsc2hs dans le cadre de la construction.
$ cabal configure
Resolving dependencies...
Configuring intmax-0.0...
$ cabal build
Prerocessing executables for intmax-0.0...
Building intmax-0.0...
[1 of 1] Compiling Main ( dist\build\intmax\intmax-tmp\IntMax.hs, dist\build\intmax\intmax-tmp\Main.o )
Linking dist\build\intmax\intmax.exe ...
$ ./dist/build/intmax/intmax
2147483647
Notez que vous souhaiterez rompre les lignes avec plusieurs constantes. Supposons que vous soyez en train d'assembler un bitfield à FormatMessage . Vous aurez envie de l'écrire comme
flags = #const FORMAT_MESSAGE_FROM_SYSTEM
.|.
#const FORMAT_MESSAGE_IGNORE_INSERTS
Les mettre tous sur une seule ligne entraînera des erreurs de syntaxe.
Autres conseils
GHC s'éloigne de -fvia-c
pour aller à -fasm
dans la mesure du possible.
Un effet secondaire est que votre programme peut être compilé sans utiliser aucun en-tête C, même en mode -fvia-c
, afin de garantir que les résultats de la compilation sont fonctionnellement identiques à ceux de GHC dans Mode -fasm
.
Il est donc nécessaire d'utiliser hsc2hs
, c2hs
ou d'autres préprocesseurs exécutés avant GHC compile les sources.
c2hs
supporte de manière native les constantes enum
... ça fait un moment, mais je pense que quelque chose comme cela est correct.
#c
enum Foo = { Bar, Baz };
void something(enum Foo foo) {}
#endc
{#enum Foo#}
somethingBar = {#call pure something#} (cFromEnum Bar)
#define
Les constantes sont plus compliquées. Je les ai toujours simplement copiés en ligne, ou utilisé un C supplémentaire pour les transformer ensuite en enums ou en variables const.