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*));