[MLton] MLton import headers

Wesley W. Terpstra wesley at terpstra.ca
Sat Oct 4 09:37:31 PDT 2008


On Sat, Oct 4, 2008 at 4:50 PM, Matthew Fluet <fluet at tti-c.org> wrote:
>> So you would propose that I always require the user to
>> #define PART_OF_X / STATIC_LINK_X / DYNAMIC_LINK_X before #include'ing
>> the header?
>
> Not necessarily.  What is 'best/common' practice?  Doing a
> 'grep -r "(visibility(" /usr/include/*' (on an x86-linux) turns up some
> headers that use it, but none appear to demand a
> #define PART_OF/STATIC_LINK/DYNAMIC_LINK in order to control the visibility.

On linux you can ignore the difference of STATIC_LINK and
DYNAMIC_LINK. Thus most projects do. Libraries that must also work as
a dll on windows are the only ones which have to care.

All library projects provide some form of 'PART_OF', but it differs on
a library-to-library basis. The most common approach is to provide a
public header and one or more private headers. Examples of this are
gdtoa, gmp, and sqlite3. Some libraries also use a macro. For example,
gmp uses __GMP_WITHIN_GMP.

gmp also distinguishes static/dynamic linkage with __GMP_LIBGMP_DLL.
My approach follows gmp very closely. gmp sets GMP_LIBGMP_DLL at
library creation time depending on if it is a static or dynamic
library. It also has this to say:
      AC_MSG_ERROR([cannot build both static and DLL, since gmp.h is
different for each. Use "--disable-static --enable-shared" to build
just a DLL.])

I also set STATIC/DYNAMIC_LINK to some default in our export header
based on static/dynamic output. I've just allowed the user to override
it.

Very few libraries can compile to a PIC archive. glibc is one example,
but it clearly has no need to be portable to a non-ELF platform. This
is the only case where I currently leave no default. There is
definitely no 'best practice' for this type of library.

The current MLton approach is: the export header is exactly the same
for all output formats, except that the default
PART_OF/STATIC_LINK/DYNAMIC_LINK differs. The user can be explicit and
override this default.

On an ELF system you can use the export headers for both
static/dynamic, because EXERNAL/PUBLIC are identical on that target.
Thus you can do like most linux programs and supply one header that
works for both static and dynamic libraries.

My personal opinion is that removing the default and requiring the
user to always specify the linkage would be surprising when compared
to how one typically uses C libraries. There are only two cases where
the default is 'wrong'. 1) PIC archives, which are a corner case very
few projects need. In this case the header has no default and forces
you to pay attention. 2) You are compiling a library including ML code
and C code. In this case we require:
  #define PART_OF_XYZ
  #include "xyz.h"
inside your C files instead of:
  #include "xyz.h"
  #include "xyz-private.h"
This doesn't seem particularly onerous or strange to me. You're
cooperating with MLton to build a library in this case, so it's fair
for us to have a (not-so-uncommon) convention you need to be aware of.

> I don't see how functors and/or the ml basis sytem help here.  Neither allow
> for control-flow or conditional compilation.

I meant to use the mlb-path-map approach. You can write your
library-dependent code as a functor and then bind it to one of the two
structures in a file chosen depending on a path variable.

At any rate, I no longer think the ML export header is necessary. The
only situtation it seems reasonable for an ML program to use an ML
library via FFI is if there was a pure C library between them, in
which case you probably shouldn't be using the internal ML library
anyway, but rather the C library's wrappers.

What I do think we need is a new annotation, 'defaultImport
public/external'. This way your 'prim.sml' that does all the
_import/_address/_symbol'ing can be easily switched between
static/dynamic import.



More information about the MLton mailing list