Compiler modes / FFI / forcing CPP

Philip Hölzenspies p.k.f.holzenspies at utwente.nl
Wed Apr 29 18:48:43 EDT 2009


Dear GHC-ers,

 From earlier questions, it seems no one wants to get down and dirty  
with linker tricks in ghc. I'm now looking over an alternative solution.

I'm currently trying to use SDL. There's a wrapper on hackage, which  
works fine under Linux, but it takes some tinkering under Mac OS X,  
because OS X needs instantiated Cocoa stuff for the SDL entry point.  
Long story short, to use SDL with ghc on the OS X, a little wrapper c- 
file needs to be written, because the linker will find a 'main'  
function in libSDLmain.a which expects a function 'SDL_main' as an  
entry point into the user code.

I have written a small c file that can be used to wrap around any  
haskell module (see below), based on the macro (cpp) definition of  
MODNAME. I can compile this c file with gcc, for, let's say a module  
Foo with entry point Foo.bar (so, if we could still have ghc make the  
entry point, we would say ghc -main-is Foo.bar):

gcc -c -DMODNAME=Foo -D"ENTRYPOINT=bar();" -o Foo_entry.o entry.c

However, this only works after I explicitly add ghc's "include" dir to  
my search path so that HsFFI.h can be found. Before I had this pre- 
processor trick, I could simply feed the c file to ghc, together with  
all my haskell files. Ghc then simply adds the correct includes and  
feeds the c file to the c compiler. Unfortunately, giving ghc the  
above -D options doesn't do much good.

The problem seems to lie with the suffix recognition ghc does. I took  
this from [1]. With the -cpp switch, the c pre-processor is used, but  
only when the file has a .hs suffix. The c compiler is only run when  
the file has a .c suffix. Using -x .hs puts the file correctly through  
the c pre-processor, but then fails to compile it, because it's not  
haskell code. Using -x .c doesn't do pre-processing (even with -cpp).  
I tried to compile this wrapper using this command (assume now that we  
have Foo.hsMain as an entry point):

   ghc -cpp -pgmP cc -optP-E -DMODNAME=Foo -o Foo_entry.o entry.c

(Notice that you can't just use cpp, because on OS X that's a shell  
script that doesn't provide CPPs full strength, so you want "cc -E".)  
This doesn't work:

   entry.c:27:2:  error: #error MODNAME undefined!

Trying to be more explicit as to where the -D should go:

   ghc -cpp -pgmP cc -optP-E -optP-DMODNAME=Foo -o Foo_entry.o entry.c

does exactly the same. Now faking .hs:

   ghc -cpp -pgmP cc -optP-E -optP-DMODNAME=Foo -o Foo_entry.o -x hs  
entry.c

which produces the error (coming from stdio.h inclusion):

   /usr/include/i386/_types.h:37:28: parse error on input `;'

So, I guess my question is: Is it possible to let a c input file of  
ghc pass through *both* the c pre-processor *and* the c compiler?

Kind regards,
Philip





[1] GHC User's Guide: Section 5.4: Modes of operation
  http://www.haskell.org/ghc/docs/latest/html/users_guide/modes.html



entry.c:


#ifdef MODNAME
#ifndef ENTRYPOINT
#define ENTRYPOINT hsMain();
#endif
#include <stdio.h>
#include "HsFFI.h"
#define  __HS_mangle(name)       __stginit_ ## name
#define  __Xpand_HS_mangle(nm)   __HS_mangle(nm)
#define  __hs_mangled_module     __Xpand_HS_mangle( MODNAME )
#define  __pack_quotes(x)        #x
#define  __calc_include(x)       __pack_quotes(x##_stub.h)
#define  __Xpand_calc_include(x) __calc_include(x)
#include __Xpand_calc_include(MODNAME)

extern void __hs_mangled_module ( void );

int
SDL_main(int argc, char *argv[])
{
	hs_init(&argc, &argv);
	hs_add_root(__hs_mangled_module);
	ENTRYPOINT
	hs_exit();
	return 0;
}
#else /* MODNAME */
#error MODNAME undefined!
#endif /* MODNAME */



More information about the Glasgow-haskell-users mailing list