[MLton] Support for link options in ML Basis files

Matthew Fluet fluet@cs.cornell.edu
Tue, 18 Jan 2005 09:03:54 -0500 (EST)

> >  * MLton's FFI isn't expressive enough to pass a struct/union from ML to
> >    C.  I can fake it on the x86 because the calling convention is to pass
> >    the struct "in pieces", so one can simulate the call by extracting the
> >    struct fields and passing them in order.  Unfortunately, this doesn't
> >    work on all architectures.
> Can we avoid portability problems by automatically generating a
> wrapper to translate between the calling convention we understand
> (n-ary C functions with basic types) and the calling convention we
> don't (passing C structs)?

That is an option.  It is more information to carry around in CFunction.t,
but it would appear to get us most of the way there.  I don't know how to
designate unions (nor how to make an appropriate wrapper for them).

Also, it doesn't solve the circular dependencies issue.  (Although,
C-code that gives rise to these situations may not be valid; gcc usually
gives me a warning when I try compiling it.)

The problem is that on the ML side, ML-NLFFI always passes structs/unions
around as pointers.  So, if C-code gave rise to:

> For example, if someone does
>    _import "f": char * {x: int, y: double} -> unit;
> then on the SML side we turn this into
>   fn (c, {x, y}) => _import "f_wrapper": char * int * double -> unit; (c, x, y)

then mlnlffigen still wants to export a "wrapped" version of "f" that
takes care of converting to and from ML representations.  So, it would
generate a function that is the ML equivalent of:

void call_f (char c, struct zzz *z) {
  f_wrapper (c, z->i, z->d);

In order to translate this into ML, we use the generated code for
extracting fields of a  struct zzz.

I'll note that what SML/NJ does is the following; rather than passing the
struct in pieces to the wrapper, it passes the pointer.  So,

  _import "f": char * {x: int, y: double} -> unit;

turns into

  fn (c, p) => _import "f_wrapper": char * pointer -> unit; (c, p)

and in the codegen, they produce the following:

struct zzz {
	int i;
	double d;

void f (char c, struct zzz z);

void f_wrapper (char c, struct zzz *z) {
	f (c, *z);

> >  * mlnlffigen also has it's shortcomings, independent of MLton.  The most
> >    glaring of which is that it doesn't export #define constants.  It is a
> >    recognized problem, but as of right now there doesn't appear to be a
> >    solution out there.  I suspect it requires modifying the ckit Library.
> Might it work to use the same approach that we use for
> build/lib/<target>/constants?

Depends what you mean?  I believe the hope is that the programmer doesn't
need to specify which #define constants should be exported, but that might
be too much to ask of a tool.