extended foreign decls

Tyson Dowd trd at cs.mu.OZ.AU
Wed Dec 6 22:57:02 EST 2000

On 06-Dec-2000, malcolm-ffi at cs.york.ac.uk <malcolm-ffi at cs.york.ac.uk> wrote:
> Fergus writes, triggered by my suggestion of "foreign value":

[ stuff deleted ]

> I propose that
>     foreign code <language-id> { <code> }
> should simply cause the verbatim copying of the <code> part into a
> file to be compiled by the appropriate foreign compiler.  That's all.
> Nothing fancy.

Actually I should point out that sometimes the Mercury FFI does do
something a little bit fancy at this point.  

First is that for the Managed C++ backend (an extension of C++ to allow
it to generate garbage collected types and bytecode for the Microsoft
.NET Frameworks), it will automatically create a class and will insert
foreign_decls above the class definition, and foreign_codes inside the
class definition.  Any predicate/function implementations are created as
static methods of the class.

> > 	:- pragma foreign_decls(c, "
> > 		#define _POSIX_SOURCE 1
> > 		extern int my_global;
> > 	").
> Fergus, could you enlighten me some more about the difference between
> the foreign_decls and foreign_code pragmas?  I'm afraid I can't
> immediately see why you have both.

There is a difference in the way such code is treated with respect to
optimization.  We haven't formalized the exact definition of the
difference just yet -- this is an outstanding bug in our documentation.

The implementation is free to split each foreign_code fragment into (for
example) a separate file for each fragment, or to cross-module inline
such fragments.  Mercury can do both of these optimizations.

But such code might need to share a common set of declarations.
So foreign_decls can be viewed as the "common" declarations for all foreign
code in that module.  Each output file that uses a foreign_code fragment must
also include (possibly by #include, possibly by textual subsitution) the
foreign_decls part.

The declarations in the foreign_decls must not define any storage.
In C they will correspond very closely to a "header file".  

The definitions in foreign_code must not rely upon definitions in any
other foreign_code.  They can rely on declarations in the foreign_decls,

> > the Mercury compiler extracts the foreign_decl and
> > foreign_code stuff, wrapping code in the second form of foreign_code
> > up inside appropriate function definitions, and puts them all in a
> > separate file that it then invokes the foreign language compiler on.
> And I would expect a Haskell compiler to do something similar.  For C,
> Java, and the like, this would be fairly easy for the compiler writer
> to provide.  But in the general case, I'd guess that there should be
> some sort of configurable "plugin" interface, by which an ordinary
> user could tell the the Haskell compiler about
>     foreign language name:	Wibble
>     compiler name:		wblc
>     default options:		-fno-flubble-mangling
>     extra linking options:	-lwibblelib
> and such like, so that they could use the FFI for whatever language
> they pleased.

This would (possibly) be enough to let them use whatever *compiler* they
want, but not necessarily whatever *language*.  Different languages have
different calling conventions and marshalling requirements.  I would
expect you also need a programmatic interface to allow plugins to be
written to handle these (sort of like writing a little code generator
for each language).

> > I certainly consider the mechanism that Mercury
> > uses to be elegant enough to be the official Mercury FFI,
> > and I hope our standards are not so much lower than yours ;-)
> I agree.  In fact, I was mighty impressed to see that you'd already
> implemented my proposal in Mercury before I even proposed it.  :-)

This is a pretty recent addition to Mercury.  We've been thinking about
it for a while.

The need has come up because as we target new backends we need to
re-target the Mercury library, which involves re-writing a lot of C code
into {Java, Managed C++, C#, whatever}.

Also we found that we were doing almost all of this work anyway in the
MCORBA tool, because it interfaced with C++.  MCORBA was generating C
code to call C++, and C++ code to talk to the CORBA ORB.

       Tyson Dowd           # 
                            #  Surreal humour isn't everyone's cup of fur.
     trd at cs.mu.oz.au        # 
http://www.cs.mu.oz.au/~trd #

More information about the FFI mailing list