problems with FFI including h files
Alastair Reid
reid@cs.utah.edu
03 Jun 2002 15:57:08 +0100
> Anyone have any ideas that don't have such a big impact?
What we did in Hugs (for GreenCard stuff) was create a header file
containing _only_ the things needed by ffi'd code (example attached).
Since it was such a short file, it wasn't too hard to avoid
nameclashes.
This works because the ffi-generated wrappers are very simple and
there's no compiled Haskell code in the same file.
In GHC, I see two options:
1) Compilation generates two C files:
1) A file of ffi wrappers.
These pull in ffi-specified headers, HsFFI.h and maybe a half dozen
function prototypes giving access to GHC runtime internals.
2) A file of compiled Haskell code.
These pull in any GHC headers they like but not ffi-specified headers.
Disadvantage: extra layer of indirection on ffi calls.
2) Restrict ffi to invoking functions not macros.
In this case, GHC generates function prototypes itself based on the
Haskell type and ignores the header files.
If you want to detect mismatches between function prototypes in the C
header file and the GHC-generated prototypes, you could generate a C
file like this:
#include <ffi_specified_headers.h>
#include <ghc_generated_prototypes.h>
GHC_type_for_f *f_pointer = &f;
and you'll get told of many mismatches.
--
Alastair
This is roughly how the Hugs FFI header file will look once my current
hacking on it is finished. The current header file contains little
more than the final struct and a few typedefs.
typedef char HsChar;
typedef int HsInt;
typedef int8_t HsInt8;
typedef int16_t HsInt16;
typedef int32_t HsInt32;
typedef int64_t HsInt64;
typedef unsigned int HsWord;
typedef uint8_t HsWord8;
typedef uint16_t HsWord16;
typedef uint32_t HsWord32;
typedef uint64_t HsWord64;
typedef float HsFloat;
typedef double HsDouble;
typedef int HsBool;
typedef void* HsAddr;
typedef void* HsPtr;
typedef void (*HsFunPtr)(void);
typedef void* HsForeignPtr;
typedef void* HsStablePtr;
#define HS_CHAR_MIN 0
#define HS_CHAR_MAX 0xFF
#define HS_BOOL_FALSE 0
#define HS_BOOL_TRUE 1
#define HS_BOOL_MIN HS_BOOL_FALSE
#define HS_BOOL_MAX HS_BOOL_TRUE
#define HS_INT_MIN __INT32_MIN
#define HS_INT_MAX __INT32_MAX
#define HS_INT8_MIN __INT8_MIN
#define HS_INT8_MAX __INT8_MAX
#define HS_INT16_MIN __INT16_MIN
#define HS_INT16_MAX __INT16_MAX
#define HS_INT32_MIN __INT32_MIN
#define HS_INT32_MAX __INT32_MAX
#define HS_INT64_MIN __INT64_MIN
#define HS_INT64_MAX __INT64_MAX
#define HS_WORD8_MAX __UINT8_MAX
#define HS_WORD16_MAX __UINT16_MAX
#define HS_WORD32_MAX __UINT32_MAX
#define HS_WORD64_MAX __UINT64_MAX
#define HS_FLOAT_RADIX FLT_RADIX
#define HS_FLOAT_ROUNDS FLT_ROUNDS
#define HS_FLOAT_EPSILON FLT_EPSILON
#define HS_FLOAT_DIG FLT_DIG
#define HS_FLOAT_MANT_DIG FLT_MANT_DIG
#define HS_FLOAT_MIN FLT_MIN
#define HS_FLOAT_MIN_EXP FLT_MIN_EXP
#define HS_FLOAT_MIN_10_EXP FLT_MIN_10_EXP
#define HS_FLOAT_MAX FLT_MAX
#define HS_FLOAT_MAX_EXP FLT_MAX_EXP
#define HS_FLOAT_MAX_10_EXP FLT_MAX_10_EXP
#define HS_DOUBLE_RADIX DBL_RADIX
#define HS_DOUBLE_ROUNDS DBL_ROUNDS
#define HS_DOUBLE_EPSILON DBL_EPSILON
#define HS_DOUBLE_DIG DBL_DIG
#define HS_DOUBLE_MANT_DIG DBL_MANT_DIG
#define HS_DOUBLE_MIN DBL_MIN
#define HS_DOUBLE_MIN_EXP DBL_MIN_EXP
#define HS_DOUBLE_MIN_10_EXP DBL_MIN_10_EXP
#define HS_DOUBLE_MAX DBL_MAX
#define HS_DOUBLE_MAX_EXP DBL_MAX_EXP
#define HS_DOUBLE_MAX_10_EXP DBL_MAX_10_EXP
typedef struct {
/* evaluate next argument */
HsInt (*getInt) Args(());
HsWord (*getWord) Args(());
HsAddr (*getAddr) Args(());
HsFloat (*getFloat) Args(());
HsDouble (*getDouble) Args(());
HsChar (*getChar) Args(());
HugsForeign (*getForeign) Args(());
HsStablePtr (*getStablePtr) Args(());
/* push part of result */
void (*putInt) Args((HsInt));
void (*putWord) Args((HsWord));
void (*putAddr) Args((HsAddr));
void (*putFloat) Args((HsFloat));
void (*putDouble) Args((HsDouble));
void (*putChar) Args((HsChar));
void (*putForeign) Args((HugsForeign, void (*)(HugsForeign)));
void (*putStablePtr) Args((HsStablePtr));
/* return n values in IO monad or Id monad */
void (*returnIO) Args((HugsStackPtr, int));
void (*returnId) Args((HugsStackPtr, int));
int (*runIO) Args((int));
/* free a stable pointer */
void (*freeStablePtr) Args((HsStablePtr));
/* register the prim table */
void (*registerPrims) Args((struct primInfo*));
/* garbage collect */
void (*garbageCollect) Args(());
/* API3 additions follow */
HsStablePtr (*lookupName) Args((char*, char*));
void (*ap) Args((int));
void (*getUnit) Args(());
void* (*mkThunk) Args((void*, HsStablePtr));
void (*freeThunk) Args((void*));
HsBool (*getBool) Args(());
void (*putBool) Args((HsBool));
/* API4 additions follow */
HsInt8 (*getInt8) Args(());
HsInt16 (*getInt16) Args(());
HsInt32 (*getInt32) Args(());
HsInt64 (*getInt64) Args(());
HsWord8 (*getWord8) Args(());
HsWord16 (*getWord16) Args(());
HsWord32 (*getWord32) Args(());
HsWord64 (*getWord64) Args(());
HsPtr (*getPtr) Args(());
HsFunPtr (*getFunPtr) Args(());
HsForeignPtr (*getForeignPtr) Args(());
void (*putInt8) Args((HsInt8));
void (*putInt16) Args((HsInt16));
void (*putInt32) Args((HsInt32));
void (*putInt64) Args((HsInt64));
void (*putWord8) Args((HsWord8));
void (*putWord16) Args((HsWord16));
void (*putWord32) Args((HsWord32));
void (*putWord64) Args((HsWord64));
void (*putPtr) Args((HsPtr));
void (*putFunPtr) Args((HsFunPtr));
void (*putForeignPtr) Args((HsForeignPtr));
} HugsAPI4;
extern HugsAPI4* hugsAPI4 Args((Void));
typedef Void (*InitModuleFun4) Args((HugsAPI4*));