[MLton-user] SVN r6941 MLton/MinGW32 and FFI

Matthew Fluet fluet at tti-c.org
Tue Nov 11 10:04:43 PST 2008


On Tue, 11 Nov 2008, Wesley W. Terpstra wrote:
> On Tue, Nov 11, 2008 at 2:36 PM, Matthew Fluet <fluet at tti-c.org> wrote:
>> It is one of the examples from <src>/doc/examples/ffi.
>> These examples really should work 'out of the box'.
>
> I didn't know about these files. I've started updating them to use
> symbol scopes. I've noticed a couple of things:
>
> 1. ffi-import.c uses GC_getArrayLength from "platform.h"! Is this
> really supposed to be user-accessible? If yes, should it be a private
> symbol only accessible within the DSO, a public symbol (in which case
> it needs a libname_ prefix), or both?

It is a function defined in libmlton.a, so I would guess that it should be 
a private symbol, only accessible within the DSO.  (Just like all the 
other runtime functions.)  For libraries, I think the current setup is 
good -- the only visible symbols are those explicitly 'public' exported 
(and the auto-generated 'libname_open' and 'libname_close' functions).

With regards to whether users should actually use GC_getArrayLength, we 
don't really advertise it, but neither is it a particularly subtle 
operation.  And, it is genuinely useful (though, getting the length and 
passing it through the FFI along with the array pointer wouldn't been 
terribly difficult either).  I don't think there is any way to really 
distinguish between visible functions in libmlton.a that are available for 
use in mlton generated .c and .s files, but not available for user .c 
code.

> 2. iimport.c uses dlopen/dlclose/dlsym. platform/mingw.c defines
> these... which is a problem since the runtime is statically linked,
> but libdl is dynamically linked. Perhaps these should be public
> libname_ symbols, private MLton_dlopen/close/sym, or both?

To clarify: the issue is that on *NIX platforms (including MacOSX), 
dl{open,close,sym,error,...} are pulled from dynamically linked shared 
libraries.  That is, they are imported from another DSO.  Thus, for these 
platforms, the 'external' attribute should be used on the _import.

MinGW doesn't provide dl{open,close,...} in a (standard) dynamically 
linked shared library.  Vesa added rudimentary emulation in 
<src>/runtime/platform/mingw.c (r4862, 20061127); thus dl{open,close,...} 
are pulled from libmlton.a.  That is, they are imported from the same DSO. 
Thus, for this platform, the 'private' attribute should be used on the 
_import.

Personally, I think that MLton should not be attempting to provide 
non-essential functionality that is missing on a platform.  My suspicion 
is that 99% of all MLton compiled SML programs will not need 
dl{open,close,...} support.  Of the remaining 1%, most will probably be on 
*NIX platforms, where dl{open,close,...} are provided by standard system 
libraries.  (You can see from the <src>/doc/examples/ffi/Makefile iimport 
target that some *NIX platforms require extra link options to find the 
library; MLton doesn't default to including those link options, because 
they are not essential functionality (e.g., required by some of the Basis 
Library implementation).)  That leaves a very small number of programs 
that are on Windows (via MinGW, since, apparently, Cygwin provides 
dl{open,close,...}).  If they are MinGW exclusive, they can use the Win32 
specific {Load,Free}Library/GetProcAddress functions.

The remaining (infinitesmal) programs are ones that require dlopen-ing 
libraries and are trying to stay source compatible for *NIX and 
Windows/MinGW. For those situations, there are more robust solutions than 
MLton emulating dl{open,close,...} for MinGW.  One is to use MLB 
path-variables to provide a compatibility module:

dynlink.mlb:
local
   dyn-link.sig
   platform/dyn-link.$(TARGET_ARCH)-$(TARGET_OS).mlb
in
   signature DYN_LINK
   structure DynLink
end

platform/dynlink.x86-linux.mlb:
dynlink.dlfcn.mlb

platform/dyn-link.dlfcn.mlb:
dyn-link.dlfnc.sml

platform/dyn-link.dlfcn.sml:
structure DynLink :> DYN_LINK =
struct
       type hndl = MLton.Pointer.t
       type mode = Word32.word

       val dlopen =
          _import "dlopen" external : string * mode -> hndl;
       ...
end

platform/dynlink.x86-mingw.mlb:
dynlink.win32.mlb

platform/dynlink.win32.mlb:
dynlink.win32.sml

platform/dynlink.win32.sml:
structure DynLink :> DYN_LINK =
struct
       type hndl = MLton.Pointer.t

       val loadLibrary  =
          _import "LoadLibrary" stdcall external : string -> hndl;
       ...
end

Alternatively, use the GNU libtool libtldl library, whose express purpose 
is to provide a uniform interface to various system specific dynamic 
library mechanisms.  Assuming that libtldl is available as a dynamically 
linked shared library (i.e., a different DSO than the program) on all the 
platforms of interest, then its functions may all be _import-ed with 
'external' scope.

> What would make most sense to me:
> * MLton_{dlopen,dlclose,dlsym,getArrayLength} are private symbols
> available within the DSO
> * GC_getArrayLength is also a private alias for compatibility
> * libname_getArrayLength are public symbols available to users of a
> DSO. Perhaps the dl* symbols too.

I (respectfully) disagree on all counts ;-)

- MLton shouldn't be providing dl{open,close,...} in any form.
- GC_getArrayLength isn't advertised, so there is no need to 'bless' it
   with a MLton_getArrayLength name.  (We should eliminate its use from the
   <src>/doc/examples/ffi examples.)
- No functions should be public symbols available to users of a DSO other
   than those specified by the user.  If a function needs the length of an
   array, arrange the interface to pass the length along with the array
   pointer.

>>> See http://mlton.org/LibrarySupport , suggestions to improve the
>>> documentation are welcome.
>>
>> If the symbol scopes can't be given sensible defaults for executables that
>> match the behavior of previous versions, then they really need to be
>> documented as well at:
>>  http://mlton.org/ForeignFunctionInterfaceSyntax
>
> I agree. However, that page corresponds to the release version of
> MLton, which doesn't have symbol scopes.

It might be a good idea to clone the page (say, as 
NextRelease/ForeignFunctionInterfaceSyntax) to make current documentation 
available somewhere.  Also, it makes it easier to switch in when the time 
comes.



More information about the MLton-user mailing list