<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta name="robots" content="index,nofollow"> <title>CallingFromSMLToCFunctionPointer - MLton Standard ML Compiler (SML Compiler)</title> <link rel="stylesheet" type="text/css" charset="iso-8859-1" media="all" href="common.css"> <link rel="stylesheet" type="text/css" charset="iso-8859-1" media="screen" href="screen.css"> <link rel="stylesheet" type="text/css" charset="iso-8859-1" media="print" href="print.css"> <link rel="Start" href="Home"> </head> <body lang="en" dir="ltr"> <script src="http://www.google-analytics.com/urchin.js" type="text/javascript"> </script> <script type="text/javascript"> _uacct = "UA-833377-1"; urchinTracker(); </script> <table bgcolor = lightblue cellspacing = 0 style = "border: 0px;" width = 100%> <tr> <td style = " border: 0px; color: darkblue; font-size: 150%; text-align: left;"> <a class = mltona href="Home">MLton MLTONWIKIVERSION</a> <td style = " border: 0px; font-size: 150%; text-align: center; width: 50%;"> CallingFromSMLToCFunctionPointer <td style = " border: 0px; text-align: right;"> <table cellspacing = 0 style = "border: 0px"> <tr style = "vertical-align: middle;"> </table> <tr style = "background-color: white;"> <td colspan = 3 style = " border: 0px; font-size:70%; text-align: right;"> <a href = "Home">Home</a> <a href = "TitleIndex">Index</a> </table> <div id="content" lang="en" dir="ltr"> Just as MLton can <a href="CallingFromSMLToC">directly call C functions</a>, it is possible to make indirect function calls; that is, function calls through a function pointer. MLton extends the syntax of SML to allow expressions like the following: <pre>_import * : MLton.Pointer.t -> real * char -> int; </pre><p> This expression denotes a function of type <pre>MLton.Pointer.t -> real * char -> int</pre>whose behavior is implemented by calling the C function at the address denoted by the <tt>MLton.Pointer.t</tt> argument, and supplying the C function two arguments, a <tt>double</tt> and an <tt>int</tt>. The C function pointer may be obtained, for example, by the dynamic linking loader (<tt>dlopen</tt>, <tt>dlsym</tt>, ...). </p> <p> The general form of an indirect <tt>_import</tt> expression is: </p> <pre>_import * attr... : cPtrTy -> cFuncTy; </pre><p> The type and the semicolon are not optional. </p> <h2 id="head-0f01ed56a1e32a05e5ef96e4d779f34784af9a96">Example</h2> <p> This example uses <tt>dlopen</tt> and friends (imported using normal <tt>_import</tt>) to dynamically load the math library (<tt>libm</tt>) and call the <tt>cos</tt> function. Suppose <tt>iimport.sml</tt> contains the following. </p> <p> <pre class=code><B><FONT COLOR="#0000FF">signature</FONT></B> DYN_LINK = <B><FONT COLOR="#0000FF">sig</FONT></B> <B><FONT COLOR="#A020F0">type</FONT></B><B><FONT COLOR="#228B22"> hndl </FONT></B><B><FONT COLOR="#A020F0">type</FONT></B><B><FONT COLOR="#228B22"> mode </FONT></B><B><FONT COLOR="#A020F0">type</FONT></B><B><FONT COLOR="#228B22"> fptr </FONT></B><B><FONT COLOR="#A020F0">val</FONT></B> dlopen : string * mode -> hndl <B><FONT COLOR="#A020F0">val</FONT></B> dlsym : hndl * string -> fptr <B><FONT COLOR="#A020F0">val</FONT></B> dlclose : hndl -> unit <B><FONT COLOR="#A020F0">val</FONT></B> RTLD_LAZY : mode <B><FONT COLOR="#A020F0">val</FONT></B> RTLD_NOW : mode <B><FONT COLOR="#0000FF">end</FONT></B> <B><FONT COLOR="#0000FF">structure</FONT></B> DynLink :> DYN_LINK = <B><FONT COLOR="#0000FF">struct</FONT></B> <B><FONT COLOR="#A020F0">type</FONT></B><B><FONT COLOR="#228B22"> hndl </FONT></B>=<B><FONT COLOR="#228B22"> MLton.Pointer.t </FONT></B><B><FONT COLOR="#A020F0">type</FONT></B><B><FONT COLOR="#228B22"> mode </FONT></B>=<B><FONT COLOR="#228B22"> Word32.word </FONT></B><B><FONT COLOR="#A020F0">type</FONT></B><B><FONT COLOR="#228B22"> fptr </FONT></B>=<B><FONT COLOR="#228B22"> MLton.Pointer.t <I><FONT COLOR="#B22222">(* These symbols come from a system libray, so the default import scope * of external is correct. *)</FONT></I> </FONT></B><B><FONT COLOR="#A020F0">val</FONT></B> dlopen = _import <B><FONT COLOR="#BC8F8F">"dlopen"</FONT></B> : string * mode -> hndl; <B><FONT COLOR="#A020F0">val</FONT></B> dlerror = _import <B><FONT COLOR="#BC8F8F">"dlerror"</FONT></B>: unit -> MLton.Pointer.t; <B><FONT COLOR="#A020F0">val</FONT></B> dlsym = _import <B><FONT COLOR="#BC8F8F">"dlsym"</FONT></B> : hndl * string -> fptr; <B><FONT COLOR="#A020F0">val</FONT></B> dlclose = _import <B><FONT COLOR="#BC8F8F">"dlclose"</FONT></B> : hndl -> Int32.int; <B><FONT COLOR="#A020F0">val</FONT></B> RTLD_LAZY = <B><FONT COLOR="#5F9EA0">0wx00001</FONT></B> <I><FONT COLOR="#B22222">(* Lazy function call binding. *)</FONT></I> <B><FONT COLOR="#A020F0">val</FONT></B> RTLD_NOW = <B><FONT COLOR="#5F9EA0">0wx00002</FONT></B> <I><FONT COLOR="#B22222">(* Immediate function call binding. *)</FONT></I> <B><FONT COLOR="#A020F0">val</FONT></B> dlerror = <B><FONT COLOR="#A020F0">fn</FONT></B> () => <B><FONT COLOR="#A020F0">let</FONT></B> <B><FONT COLOR="#A020F0">val</FONT></B> addr = dlerror () <B><FONT COLOR="#A020F0">in</FONT></B> <B><FONT COLOR="#A020F0">if</FONT></B> addr = MLton.Pointer.null <B><FONT COLOR="#A020F0">then</FONT></B> NONE <B><FONT COLOR="#A020F0">else</FONT></B> <B><FONT COLOR="#A020F0">let</FONT></B> <B><FONT COLOR="#A020F0">fun</FONT></B> loop (index, cs) = <B><FONT COLOR="#A020F0">let</FONT></B> <B><FONT COLOR="#A020F0">val</FONT></B> w = MLton.Pointer.getWord8 (addr, index) <B><FONT COLOR="#A020F0">val</FONT></B> c = Byte.byteToChar w <B><FONT COLOR="#A020F0">in</FONT></B> <B><FONT COLOR="#A020F0">if</FONT></B> c = #<B><FONT COLOR="#BC8F8F">"\000"</FONT></B> <B><FONT COLOR="#A020F0">then</FONT></B> SOME (implode (rev cs)) <B><FONT COLOR="#A020F0">else</FONT></B> loop (index + <B><FONT COLOR="#5F9EA0">1</FONT></B>, c::cs) <B><FONT COLOR="#A020F0">end</FONT></B> <B><FONT COLOR="#A020F0">in</FONT></B> loop (<B><FONT COLOR="#5F9EA0">0</FONT></B>, []) <B><FONT COLOR="#A020F0">end</FONT></B> <B><FONT COLOR="#A020F0">end</FONT></B> <B><FONT COLOR="#A020F0">val</FONT></B> dlopen = <B><FONT COLOR="#A020F0">fn</FONT></B> (filename, mode) => <B><FONT COLOR="#A020F0">let</FONT></B> <B><FONT COLOR="#A020F0">val</FONT></B> filename = filename ^ <B><FONT COLOR="#BC8F8F">"\000"</FONT></B> <B><FONT COLOR="#A020F0">val</FONT></B> hndl = dlopen (filename, mode) <B><FONT COLOR="#A020F0">in</FONT></B> <B><FONT COLOR="#A020F0">if</FONT></B> hndl = MLton.Pointer.null <B><FONT COLOR="#A020F0">then</FONT></B> <B><FONT COLOR="#A020F0">raise</FONT></B> Fail (<B><FONT COLOR="#A020F0">case</FONT></B> dlerror () <B><FONT COLOR="#A020F0">of</FONT></B> NONE => <B><FONT COLOR="#BC8F8F">"???"</FONT></B> | SOME s => s) <B><FONT COLOR="#A020F0">else</FONT></B> hndl <B><FONT COLOR="#A020F0">end</FONT></B> <B><FONT COLOR="#A020F0">val</FONT></B> dlsym = <B><FONT COLOR="#A020F0">fn</FONT></B> (hndl, symbol) => <B><FONT COLOR="#A020F0">let</FONT></B> <B><FONT COLOR="#A020F0">val</FONT></B> symbol = symbol ^ <B><FONT COLOR="#BC8F8F">"\000"</FONT></B> <B><FONT COLOR="#A020F0">val</FONT></B> fptr = dlsym (hndl, symbol) <B><FONT COLOR="#A020F0">in</FONT></B> <B><FONT COLOR="#A020F0">case</FONT></B> dlerror () <B><FONT COLOR="#A020F0">of</FONT></B> NONE => fptr | SOME s => <B><FONT COLOR="#A020F0">raise</FONT></B> Fail s <B><FONT COLOR="#A020F0">end</FONT></B> <B><FONT COLOR="#A020F0">val</FONT></B> dlclose = <B><FONT COLOR="#A020F0">fn</FONT></B> hndl => <B><FONT COLOR="#A020F0">if</FONT></B> MLton.Platform.OS.host = MLton.Platform.OS.Darwin <B><FONT COLOR="#A020F0">then</FONT></B> () <I><FONT COLOR="#B22222">(* Darwin reports the following error message if you * try to close a dynamic library. * "dynamic libraries cannot be closed" * So, we disable dlclose on Darwin. *)</FONT></I> <B><FONT COLOR="#A020F0">else</FONT></B> <B><FONT COLOR="#A020F0">let</FONT></B> <B><FONT COLOR="#A020F0">val</FONT></B> res = dlclose hndl <B><FONT COLOR="#A020F0">in</FONT></B> <B><FONT COLOR="#A020F0">if</FONT></B> res = <B><FONT COLOR="#5F9EA0">0</FONT></B> <B><FONT COLOR="#A020F0">then</FONT></B> () <B><FONT COLOR="#A020F0">else</FONT></B> <B><FONT COLOR="#A020F0">raise</FONT></B> Fail (<B><FONT COLOR="#A020F0">case</FONT></B> dlerror () <B><FONT COLOR="#A020F0">of</FONT></B> NONE => <B><FONT COLOR="#BC8F8F">"???"</FONT></B> | SOME s => s) <B><FONT COLOR="#A020F0">end</FONT></B> <B><FONT COLOR="#0000FF">end</FONT></B> <B><FONT COLOR="#A020F0">val</FONT></B> dll = <B><FONT COLOR="#A020F0">let</FONT></B> <B><FONT COLOR="#0000FF">open</FONT></B> MLton.Platform.OS <B><FONT COLOR="#A020F0">in</FONT></B> <B><FONT COLOR="#A020F0">case</FONT></B> host <B><FONT COLOR="#A020F0">of</FONT></B> Cygwin => <B><FONT COLOR="#BC8F8F">"cygwin1.dll"</FONT></B> | Darwin => <B><FONT COLOR="#BC8F8F">"libm.dylib"</FONT></B> | _ => <B><FONT COLOR="#BC8F8F">"libm.so"</FONT></B> <B><FONT COLOR="#A020F0">end</FONT></B> <B><FONT COLOR="#A020F0">val</FONT></B> hndl = DynLink.dlopen (dll, DynLink.RTLD_LAZY) <B><FONT COLOR="#0000FF">local</FONT></B> <B><FONT COLOR="#A020F0">val</FONT></B> double_to_double = _import * : DynLink.fptr -> real -> real; <B><FONT COLOR="#A020F0">val</FONT></B> cos_fptr = DynLink.dlsym (hndl, <B><FONT COLOR="#BC8F8F">"cos"</FONT></B>) <B><FONT COLOR="#0000FF">in</FONT></B> <B><FONT COLOR="#A020F0">val</FONT></B> cos = double_to_double cos_fptr <B><FONT COLOR="#0000FF">end</FONT></B> <B><FONT COLOR="#A020F0">val</FONT></B> _ = print (concat [<B><FONT COLOR="#BC8F8F">" Math.cos(2.0) = "</FONT></B>, Real.toString (Math.cos <B><FONT COLOR="#5F9EA0">2.0</FONT></B>), <B><FONT COLOR="#BC8F8F">"\n"</FONT></B>, <B><FONT COLOR="#BC8F8F">"libm.so::cos(2.0) = "</FONT></B>, Real.toString (cos <B><FONT COLOR="#5F9EA0">2.0</FONT></B>), <B><FONT COLOR="#BC8F8F">"\n"</FONT></B>]) <B><FONT COLOR="#A020F0">val</FONT></B> _ = DynLink.dlclose hndl </PRE> </p> <p> Compile and run <tt>iimport.sml</tt>. <pre>% mlton -default-ann 'allowFFI true' \ -target-link-opt linux -ldl \ -target-link-opt solaris -ldl \ iimport.sml % iimport Math.cos(2.0) = ~0.416146836547 libm.so::cos(2.0) = ~0.416146836547 </pre> </p> <p> This example also shows the <tt>-target-link-opt</tt> option, which uses the switch when linking only when on the specified platform. Compile with <tt>-verbose 1</tt> to see in more detail what's being passed to <tt>gcc</tt>. </p> <h2 id="head-a479c9c34e878d07b4d67a73a48f432ad7dc53c8">Download</h2> <ul> <li> <p> <a href = "http://mlton.org/cgi-bin/viewsvn.cgi/*checkout*/mlton/tags/on-MLTONWIKIVERSION-release/doc/examples/ffi/iimport.sml"><img src="moin-www.png" alt="[WWW]" height="11" width="11">iimport.sml</a> </p> </li> </ul> </div> <p> <hr> Last edited on 2006-11-02 17:49:16 by <span title="76.16.241.4"><a href="MatthewFluet">MatthewFluet</a></span>. </body></html>