From 8e5eb3dfef0debc9bf9f914b1a5f5fe3d2717f89 Mon Sep 17 00:00:00 2001 From: rrt <unknown> Date: Wed, 7 Jun 2000 16:15:22 +0000 Subject: [PATCH] [project @ 2000-06-07 16:15:22 by rrt] DocBooked and moved here from hdirect/doc. --- docs/ffi.sgml | 1501 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1501 insertions(+) create mode 100644 docs/ffi.sgml diff --git a/docs/ffi.sgml b/docs/ffi.sgml new file mode 100644 index 000000000000..85f8bcf8fdc6 --- /dev/null +++ b/docs/ffi.sgml @@ -0,0 +1,1501 @@ +<!DOCTYPE Article PUBLIC "-//OASIS//DTD DocBook V3.1//EN"> + +<Article id="ffi"> + +<ArtHeader> + +<Title>A Haskell foreign function interface</Title> +<Author><OtherName>The GHC Team</OtherName></Author> +<Address><Email>glasgow-haskell-{users,bugs}@dcs.gla.ac.uk</Email> +</Address> +<Edition>version 0.99</Edition> +<PubDate>May 2000</PubDate> + +</ArtHeader> + +<Sect1 id="sec-intro"> +<Title>Introduction +</Title> + +<Para> +The motivation behind this foreign function interface(FFI) +specification is to make it possible to describe in Haskell <Emphasis>source +code</Emphasis> the interface to foreign functionality in a Haskell system +independent manner. It builds on experiences made with the previous +foreign function interfaces provided by GHC and Hugs. +</Para> + +<Para> +The FFI specified in this document is not in the market of trying to +completely bridge the gap between the actual type of an external +function, and what is a <Emphasis>convenient</Emphasis> type for that function to the +Haskell programmer. That is the domain of tools like HaskellDirect or +Green Card, both of which are capable of generating Haskell code that +uses this FFI. +</Para> + +<Para> +The FFI can be split up into two complementary halves; one half that +provides Haskell constructs for importing foreign functionality into +Haskell, the other which lets you expose Haskell functions to the +outside world. We start with the former, how to import external +functionality into Haskell. +</Para> + +</Sect1> + +<Sect1 id="sec-primitive"> +<Title>Calling foreign functions +</Title> + +<Para> +To bind a Haskell variable name and type to an external function, we +introduce a new construct: <Literal>foreign import</Literal>. It defines the type of a Haskell function together with the name of an external function that actually implements it. The syntax of <Literal>foreign import</Literal> construct is as follows: +</Para> + +<Para> + +<ProgramListing> +topdecl + : ... + .. + | 'foreign' 'import' [callconv] [ext_fun] ['unsafe'] varid '::' prim_type +</ProgramListing> + +</Para> + +<Para> +A <Literal>foreign import</Literal> declaration is only allowed as a toplevel +declaration. It consists of two parts, one giving the Haskell type +(<Literal>prim_type</Literal>), Haskell name (<Literal>varid</Literal>) and a flag indicating whether the +primitive is unsafe, the other giving details of the name of the +external function (<Literal>ext_fun</Literal>) and its calling interface +(<Literal>callconv</Literal>.) +</Para> + +<Para> +Giving a Haskell name and type to an external entry point is clearly +an unsafe thing to do, as the external name will in most cases be +untyped. The onus is on the programmer using <Literal>foreign import</Literal> to +ensure that the Haskell type given correctly maps on to the +type of the external function. Section +<XRef LinkEnd="sec-mapping"> specifies the mapping from +Haskell types to external types. +</Para> + +<Sect2 id="sec-prim-name"> +<Title>Giving the external function a Haskell name +</Title> + +<Para> +The external function has to be given a Haskell name. The name +must be a Haskell <Literal>varid</Literal>, so the language rules regarding +variable names must be followed, i.e., it must start with a +lower case letter followed by a sequence of alphanumeric +(`in the Unicode sense') characters or '. + +<Footnote> +<Para> +Notice that with Haskell 98, underscore ('_') is included in +the character class <Literal>small</Literal>. +</Para> +</Footnote> + +</Para> + +<Para> +<ProgramListing> +varid : small ( small | large | udigit | ' )* +</ProgramListing> +</Para> + +</Sect2> + +<Sect2 id="sec-prim-ext-name"> +<Title>Naming the external function +</Title> + +<Para> +The name of the external function consists of two parts, +one specifying its location, the other its name: +</Para> + +<Para> + +<ProgramListing> +ext_fun : ext_loc ext_name + | ext_name + +ext_name : string +ext_loc : string +</ProgramListing> + +</Para> + +<Para> +For example, +</Para> + +<Para> + +<ProgramListing> +foreign import stdcall "Advapi32" "RegCloseKey" regCloseKey :: Addr -> IO () +</ProgramListing> + +</Para> + +<Para> +states that the external function named <Function>RegCloseKey</Function> at location +<Function>Advapi32</Function> should be bound to the Haskell name <Function>regCloseKey</Function>. +For a Win32 Haskell implementation that supports the loading of DLLs +on-the-fly, this declaration will most likely cause the run-time +system to load the <Filename>Advapi32.dll</Filename> DLL before looking up the +function <Function>RegCloseKey()</Function> therein to get at the function pointer +to use when invoking <Function>regCloseKey</Function>. +</Para> + +<Para> +Compiled implementations may do something completely different, i.e., +mangle "RegCloseKey" to convert it into an archive/import library +symbol, that's assumed to be in scope when linking. The details of +which are platform (and compiler command-line) dependent. +</Para> + +<Para> +If the location part is left out, the name of the external function +specifies a symbol that is assumed to be in scope when linking. +</Para> + +<Para> +The location part can either contain an absolute `address' (i.e., +path) of the archive/DLL, or just its name, leaving it up to the +underlying system (system meaning both RTS/compiler and OS) to resolve +the name to its real location. +</Para> + +<Para> +An implementation is <Emphasis>expected</Emphasis> to be able to intelligently +transform the <Literal>ext_loc</Literal> location to fit platform-specific +practices for naming dynamic libraries. For instance, given the +declaration +</Para> + +<Para> + +<ProgramListing> +foreign import "Foo" "foo" foo :: Int -> Int -> IO () +</ProgramListing> + +</Para> + +<Para> +an implementation should map <Filename>Foo</Filename> to <Filename>"Foo.dll"</Filename> on a Win32 +platform, and <Filename>libFoo.so</Filename> on ELF platforms. If the lookup of the +dynamic library with this transformed location name should fail, the +implementation should then attempt to use the original name before +eventually giving up. As part of their documentation, implementations +of <Literal>foreign import</Literal> should specify the exact details of how +<Literal>ext_loc</Literal>s are transformed and resolved, including the list of +directories searched (and the order in which they are.) +</Para> + +<Para> +In the case the Haskell name of the imported function is identical to +the external name, the <Literal>ext_fun</Literal> can be omitted. i.e., +</Para> + +<Para> + +<ProgramListing> +foreign import sin :: Double -> IO Double +</ProgramListing> + +</Para> + +<Para> +is identical to +</Para> + +<Para> + +<ProgramListing> +foreign import "sin" sin :: Double -> IO Double +</ProgramListing> + +</Para> + +</Sect2> + +<Sect2 id="sec-cconv"> +<Title>Calling conventions +</Title> + +<Para> +The number of calling conventions supported is fixed: +</Para> + +<Para> + +<ProgramListing> +callconv : ccall | stdcall +</ProgramListing> + +</Para> + +<Para> +<VariableList> + +<VarListEntry> +<Term><Literal>ccall</Literal></Term> +<ListItem> +<Para> +The 'default' calling convention on a platform, i.e., the one +used to do (C) function calls. +</Para> + +<Para> +In the case of x86 platforms, the caller pushes function arguments +from right to left on the C stack before calling. The caller is +responsible for popping the arguments off of the C stack on return. +</Para> +</ListItem> +</VarListEntry> +<VarListEntry> +<Term><Literal>stdcall</Literal></Term> +<ListItem> +<Para> +A Win32 specific calling convention. The same as <Literal>ccall</Literal>, except +that the callee cleans up the C stack before returning. + +<Footnote> +<Para> +The <Literal>stdcall</Literal> is a Microsoft Win32 specific wrinkle; it used +throughout the Win32 API, for instance. On platforms where +<Literal>stdcall</Literal> isn't meaningful, it should be treated as being equal +to <Literal>ccall</Literal>. +</Para> +</Footnote> + +</Para> +</ListItem> +</VarListEntry> +</VariableList> +</Para> + +<Para> +<Emphasis remap="bf">Some remarks:</Emphasis> + +<ItemizedList> +<ListItem> + +<Para> +Interoperating well with external code is the name of the game here, +so the guiding principle when deciding on what calling conventions +to include in <Literal>callconv</Literal> is that there's a demonstrated need for +a particular calling convention. Should it emerge that the inclusion +of other calling conventions will generally improve the quality of +this Haskell FFI, they will be considered for future inclusion in +<Literal>callconv</Literal>. +</Para> +</ListItem> +<ListItem> + +<Para> +Supporting <Literal>stdcall</Literal> (and perhaps other platform-specific calling +conventions) raises the issue of whether a Haskell FFI should allow +the user to write platform-specific Haskell code. The calling +convention is clearly an integral part of an external function's +interface, so if the one used differs from the standard one specified +by the platform's ABI <Emphasis>and</Emphasis> that convention is used by a +non-trivial amount of external functions, the view of the FFI authors +is that a Haskell FFI should support it. +</Para> +</ListItem> +<ListItem> + +<Para> +For <Literal>foreign import</Literal> (and other <Literal>foreign</Literal> declarations), +supplying the calling convention is optional. If it isn't supplied, +it is treated as if <Literal>ccall</Literal> was specified. Users are encouraged +to leave out the specification of the calling convention, if possible. +</Para> +</ListItem> + +</ItemizedList> + +</Para> + +</Sect2> + +<Sect2 id="sec-prim-types"> +<Title>External function types +</Title> + +<Para> +The range of types that can be passed as arguments to an external +function is restricted (as are the range of results coming back): +</Para> + +<Para> + +<ProgramListing> +prim_type : IO prim_result + | prim_result + | prim_arg '->' prim_type +</ProgramListing> + +</Para> + +<Para> + +<ItemizedList> +<ListItem> + +<Para> +If you associate a non-IO type with an external function, you +have the same 'proof obligations' as when you make use of +<Function>IOExts.unsafePerformIO</Function> in your Haskell programs. +</Para> +</ListItem> +<ListItem> + +<Para> +The external function is strict in all its arguments. +</Para> +</ListItem> +<ListItem> + +<Para> +<Emphasis>GHC only:</Emphasis> The GHC FFI implementation provides one extension +to <Literal>prim_type</Literal>: + + +<ProgramListing> +prim_type : ... + | unsafe_arr_ty '->' prim_type + +unsafe_arr_ty : ByteArray a + | MutableByteArray i s a +</ProgramListing> + + +GHC permits the passing of its byte array primitive types +to external functions. There's some restrictions on when +they can be used; see Section <XRef LinkEnd="sec-arguments"> +for more details. +</Para> +</ListItem> + +</ItemizedList> + +</Para> + +<Para> +Section <XRef LinkEnd="sec-results"> defines +<Literal>prim_result</Literal>; Section <XRef LinkEnd="sec-arguments"> +defines <Literal>prim_arg</Literal>. +</Para> + +<Sect3 id="sec-arguments"> +<Title>Argument types +</Title> + +<Para> +The external function expects zero or more arguments. The set of legal +argument types is restricted to the following set: +</Para> + +<Para> + +<ProgramListing> +prim_arg : ext_ty | new_ty | ForeignObj + +new_ty : a Haskell newtype of a prim_arg. + +ext_ty : int_ty | word_ty | float_ty + | Addr | Char | StablePtr a + | Bool + +int_ty : Int | Int8 | Int16 | Int32 | Int64 +word_ty : Word8 | Word16 | Word32 | Word64 +float_ty : Float | Double +</ProgramListing> + +</Para> + +<Para> + +<ItemizedList> +<ListItem> + +<Para> +<Literal>ext_ty</Literal> represent the set of basic types supported by +C-like languages, although the numeric types are explicitly sized. + +The <Emphasis>stable pointer</Emphasis> <Literal>StablePtr</Literal> type looks out of place in +this list of C-like types, but it has a well-defined and simple +C mapping, see Section <XRef LinkEnd="sec-mapping"> +for details. + +</Para> +</ListItem> +<ListItem> + +<Para> +<Literal>prim_arg</Literal> represent the set of permissible argument types. In +addition to <Literal>ext_ty</Literal>, <Literal>ForeignObj</Literal> is also included. + +The <Literal>ForeignObj</Literal> type represent values that are pointers to some +external entity/object. It differs from the <Literal>Addr</Literal> type in that +<Literal>ForeignObj</Literal>s are <Emphasis>finalized</Emphasis>, i.e., once the garbage collector +determines that a <Literal>ForeignObj</Literal> is unreachable, it will invoke a +finalising procedure attached to the <Literal>ForeignObj</Literal> to notify the +outside world that we're through with using it. + +</Para> +</ListItem> +<ListItem> + +<Para> +Haskell <Literal>newtype</Literal>s that wrap up a <Literal>prim_arg</Literal> type can also +be passed to external functions. +</Para> +</ListItem> +<ListItem> + +<Para> +Haskell type synonyms for any of the above can also be used +in <Literal>foreign import</Literal> declarations. Qualified names likewise, +i.e. <Literal>Word.Word32</Literal> is legal. + +</Para> +</ListItem> +<ListItem> + +<Para> +<Literal>foreign import</Literal> does not support the binding to external +constants/variables. A <Literal>foreign import</Literal> declaration that takes no +arguments represent a binding to a function with no arguments. +</Para> +</ListItem> +<ListItem> + +<Para> +<Emphasis>GHC only:</Emphasis> GHC's implementation of the FFI provides +two extensions: + +<ItemizedList> +<ListItem> + +<Para> +Support for passing heap allocated byte arrays to an external +function + +<ProgramListing> +prim_type : ... + | prim_arg '->' prim_type + | unsafe_arr_ty '->' prim_type + +unsafe_arr_ty : ByteArray a + | MutableByteArray i s a +</ProgramListing> + + +GHC's <Literal>ByteArray</Literal> and <Literal>MutableByteArray</Literal> primitive types are +(im)mutable chunks of memory allocated on the Haskell heap, and +pointers to these can be passed to <Literal>foreign import</Literal>ed external +functions provided they are marked as <Literal>unsafe</Literal>. Since it is +inherently unsafe to hand out references to objects in the Haskell +heap if the external call may cause a garbage collection to happen, +you have to annotate the <Literal>foreign import</Literal> declaration with +the attribute <Literal>unsafe</Literal>. By doing so, the user explicitly states +that the external function won't provoke a garbage collection, +so passing out heap references to the external function is allright. + +</Para> +</ListItem> +<ListItem> + +<Para> +Another GHC extension is the support for unboxed types: + + +<ProgramListing> +prim_arg : ... | unboxed_h_ty +ext_ty : .... | unboxed_ext_ty + +unboxed_ext_ty : Int# | Word# | Char# + | Float# | Double# | Addr# + | StablePtr# a +unboxed_h_ty : MutableByteArray# | ForeignObj# + | ByteArray# +</ProgramListing> + + +Clearly, if you want to be portable across Haskell systems, using +system-specific extensions such as this is not advisable; avoid +using them if you can. (Support for using unboxed types might +be withdrawn sometime in the future.) +</Para> +</ListItem> + +</ItemizedList> + +</Para> +</ListItem> + +</ItemizedList> + +</Para> + +</Sect3> + +<Sect3 id="sec-results"> +<Title>Result type +</Title> + +<Para> +An external function is permitted to return the following +range of types: +</Para> + +<Para> + +<ProgramListing> +prim_result : ext_ty | new_ext_ty | () + +new_ext_ty : a Haskell newtype of an ext_ty. +</ProgramListing> + +</Para> + +<Para> +where <Literal>()</Literal> represents <Literal>void</Literal> / no result. +</Para> + +<Para> + +<ItemizedList> +<ListItem> + +<Para> +External functions cannot raise exceptions (IO exceptions or non-IO ones.) +It is the responsibility of the <Literal>foreign import</Literal> user to layer +any error handling on top of an external function. +</Para> +</ListItem> +<ListItem> + +<Para> +Only external types (<Literal>ext_ty</Literal>) can be passed back, i.e., returning +<Literal>ForeignObj</Literal>s is not supported/allowed. +</Para> +</ListItem> +<ListItem> + +<Para> +Haskell newtypes that wrap up <Literal>ext_ty</Literal> are also permitted. +</Para> +</ListItem> + +</ItemizedList> + +</Para> + +</Sect3> + +</Sect2> + +<Sect2 id="sec-mapping"> +<Title>Type mapping +</Title> + +<Para> +For the FFI to be of any practical use, the properties and sizes of +the various types that can be communicated between the Haskell world +and the outside, needs to be precisely defined. We do this by +presenting a mapping to C, as it is commonly used and most other +languages define a mapping to it. Table +<XRef LinkEnd="sec-mapping-table"> +defines the mapping between Haskell and C types. +</Para> + +<Para> + +<Table id="sec-mapping-table"> +<Title>Mapping of Haskell types to C types</Title> + +<TGroup Cols="6"> +<ColSpec Align="Left" Colsep="0"> +<ColSpec Align="Left" Colsep="0"> +<ColSpec Align="Left" Colsep="0"> +<ColSpec Align="Left" Colsep="0"> +<ColSpec Align="Left" Colsep="0"> +<ColSpec Align="Left" Colsep="0"> +<TBody> +<Row RowSep="1"> +<Entry>Haskell type </Entry> +<Entry> C type </Entry> +<Entry> requirement </Entry> +<Entry> range (9) </Entry> +<Entry> </Entry> +<Entry> </Entry> +</Row> +<Row> +<Entry> +<Literal>Char</Literal> </Entry> +<Entry> <Literal>HsChar</Literal> </Entry> +<Entry> unspec. integral type </Entry> +<Entry> <Literal>HS_CHAR_MIN</Literal> </Entry> +<Entry>..</Entry> +<Entry> <Literal>HS_CHAR_MAX</Literal></Entry> +</Row> +<Row> +<Entry> +<Literal>Int</Literal> </Entry> +<Entry> <Literal>HsInt</Literal> </Entry> +<Entry> signed integral of unspec. size(4) </Entry> +<Entry> <Literal>HS_INT_MIN</Literal> </Entry> +<Entry>..</Entry> +<Entry> <Literal>HS_INT_MAX</Literal></Entry> +</Row> +<Row> +<Entry> +<Literal>Int8</Literal> (2) </Entry> +<Entry> <Literal>HsInt8</Literal> </Entry> +<Entry> 8 bit signed integral </Entry> +<Entry> <Literal>HS_INT8_MIN</Literal> </Entry> +<Entry>..</Entry> +<Entry> <Literal>HS_INT8_MAX</Literal></Entry> +</Row> +<Row> +<Entry> +<Literal>Int16</Literal> (2) </Entry> +<Entry> <Literal>HsInt16</Literal> </Entry> +<Entry> 16 bit signed integral </Entry> +<Entry> <Literal>HS_INT16_MIN</Literal> </Entry> +<Entry>..</Entry> +<Entry> <Literal>HS_INT16_MAX</Literal></Entry> +</Row> +<Row> +<Entry> +<Literal>Int32</Literal> (2) </Entry> +<Entry> <Literal>HsInt32</Literal> </Entry> +<Entry> 32 bit signed integral </Entry> +<Entry> <Literal>HS_INT32_MIN</Literal> </Entry> +<Entry>..</Entry> +<Entry> <Literal>HS_INT32_MAX</Literal></Entry> +</Row> +<Row> +<Entry> +<Literal>Int64</Literal> (2,3) </Entry> +<Entry> <Literal>HsInt64</Literal> </Entry> +<Entry> 64 bit signed integral (3) </Entry> +<Entry> <Literal>HS_INT64_MIN</Literal> </Entry> +<Entry>..</Entry> +<Entry> <Literal>HS_INT64_MAX</Literal></Entry> +</Row> +<Row> +<Entry> +<Literal>Word8</Literal> (2) </Entry> +<Entry> <Literal>HsWord8</Literal> </Entry> +<Entry> 8 bit unsigned integral </Entry> +<Entry> <Literal>0</Literal> </Entry> +<Entry>..</Entry> +<Entry> <Literal>HS_WORD8_MAX</Literal></Entry> +</Row> +<Row> +<Entry> +<Literal>Word16</Literal> (2) </Entry> +<Entry> <Literal>HsWord16</Literal> </Entry> +<Entry> 16 bit unsigned integral </Entry> +<Entry> <Literal>0</Literal> </Entry> +<Entry>..</Entry> +<Entry> <Literal>HS_WORD16_MAX</Literal></Entry> +</Row> +<Row> +<Entry> +<Literal>Word32</Literal> (2) </Entry> +<Entry> <Literal>HsWord32</Literal> </Entry> +<Entry> 32 bit unsigned integral </Entry> +<Entry> <Literal>0</Literal> </Entry> +<Entry>..</Entry> +<Entry> <Literal>HS_WORD32_MAX</Literal></Entry> +</Row> +<Row> +<Entry> +<Literal>Word64</Literal> (2,3) </Entry> +<Entry> <Literal>HsWord64</Literal> </Entry> +<Entry> 64 bit unsigned integral (3) </Entry> +<Entry> <Literal>0</Literal> </Entry> +<Entry>..</Entry> +<Entry> <Literal>HS_WORD64_MAX</Literal></Entry> +</Row> +<Row> +<Entry> +<Literal>Float</Literal> </Entry> +<Entry> <Literal>HsFloat</Literal> </Entry> +<Entry> floating point of unspec. size (5) </Entry> +<Entry> (10) </Entry> +<Entry> </Entry> +<Entry> </Entry> +</Row> +<Row> +<Entry> +<Literal>Double</Literal> </Entry> +<Entry> <Literal>HsDouble</Literal> </Entry> +<Entry> floating point of unspec. size (5) </Entry> +<Entry> (10) </Entry> +<Entry> </Entry> +<Entry> </Entry> +</Row> +<Row> +<Entry> +<Literal>Bool</Literal> </Entry> +<Entry> <Literal>HsBool</Literal> </Entry> +<Entry> unspec. integral type </Entry> +<Entry> (11) </Entry> +<Entry> </Entry> +<Entry> </Entry> +</Row> +<Row> +<Entry> +<Literal>Addr</Literal> </Entry> +<Entry> <Literal>HsAddr</Literal> </Entry> +<Entry> void* (6) </Entry> +<Entry> </Entry> +<Entry> </Entry> +<Entry> </Entry> +</Row> +<Row> +<Entry> +<Literal>ForeignObj</Literal> </Entry> +<Entry> <Literal>HsForeignObj</Literal> </Entry> +<Entry> void* (7) </Entry> +<Entry> </Entry> +<Entry> </Entry> +<Entry> </Entry> +</Row> +<Row> +<Entry> +<Literal>StablePtr</Literal> </Entry> +<Entry> <Literal>HsStablePtr</Literal> </Entry> +<Entry> void* (8) </Entry> +<Entry> </Entry> +<Entry> </Entry> +<Entry> </Entry> +</Row> +<Row> +<Entry> +</Entry> +</Row> +</TBody> + +</TGroup> + +</Table> + +</Para> + +<Para> +<Emphasis remap="bf">Some remarks:</Emphasis> + +<OrderedList> +<ListItem> + +<Para> +A Haskell system that implements the FFI will supply a header file +<Filename>HsFFI.h</Filename> that includes target platform specific definitions +for the above types and values. +</Para> +</ListItem> +<ListItem> + +<Para> +The sized numeric types <Literal>Hs{Int,Word}{8,16,32,64}</Literal> have +a 1-1 mapping to ISO C 99's <Literal>{,u}int{8,16,32,64}_t</Literal>. For systems +that doesn't support this revision of ISO C, a best-fit mapping +onto the supported C types is provided. +</Para> +</ListItem> +<ListItem> + +<Para> +An implementation which does not support 64 bit integral types +on the C side should implement <Literal>Hs{Int,Word}64</Literal> as a struct. In +this case the bounds <Constant>HS_INT64_{MIN,MAX}</Constant> and <Constant>HS_WORD64_MAX</Constant> +are undefined. +</Para> +</ListItem> +<ListItem> + +<Para> +A valid Haskell representation of <Literal>Int</Literal> has to be equal to or +wider than 30 bits. The <Literal>HsInt</Literal> synonym is guaranteed to map +onto a C type that satisifies Haskell's requirement for <Literal>Int</Literal>. +</Para> +</ListItem> +<ListItem> + +<Para> +It is guaranteed that <Literal>Hs{Float,Double}</Literal> are one of C's +floating-point types <Literal>float</Literal>/<Literal>double</Literal>/<Literal>long double</Literal>. +</Para> +</ListItem> +<ListItem> + +<Para> +It is guaranteed that <Literal>HsAddr</Literal> is of the same size as <Literal>void*</Literal>, so +any other pointer type can be converted to and from HsAddr without any +loss of information (K&R, Appendix A6.8). +</Para> +</ListItem> +<ListItem> + +<Para> +Foreign objects are handled like <Literal>Addr</Literal> by the FFI, so there +is again the guarantee that <Literal>HsForeignObj</Literal> is the same as +<Literal>void*</Literal>. The separate name is meant as a reminder that there is +a finalizer attached to the object pointed to. +</Para> +</ListItem> +<ListItem> + +<Para> +Stable pointers are passed as addresses by the FFI, but this is +only because a <Literal>void*</Literal> is used as a generic container in most +APIs, not because they are real addresses. To make this special +case clear, a separate C type is used here. +</Para> +</ListItem> +<ListItem> + +<Para> +The bounds are preprocessor macros, so they can be used in +<Literal>#if</Literal> and for array bounds. +</Para> +</ListItem> +<ListItem> + +<Para> +Floating-point limits are a little bit more complicated, so +preprocessor macros mirroring ISO C's <Filename>float.h</Filename> are provided: + +<ProgramListing> +HS_{FLOAT,DOUBLE}_RADIX +HS_{FLOAT,DOUBLE}_ROUNDS +HS_{FLOAT,DOUBLE}_EPSILON +HS_{FLOAT,DOUBLE}_DIG +HS_{FLOAT,DOUBLE}_MANT_DIG +HS_{FLOAT,DOUBLE}_MIN +HS_{FLOAT,DOUBLE}_MIN_EXP +HS_{FLOAT,DOUBLE}_MIN_10_EXP +HS_{FLOAT,DOUBLE}_MAX +HS_{FLOAT,DOUBLE}_MAX_EXP +HS_{FLOAT,DOUBLE}_MAX_10_EXP +</ProgramListing> + +</Para> +</ListItem> +<ListItem> + +<Para> +It is guaranteed that Haskell's <Literal>False</Literal>/<Literal>True</Literal> map to +C's <Literal>0</Literal>/<Literal>1</Literal>, respectively, and vice versa. The mapping of +any other integral value to <Literal>Bool</Literal> is left unspecified. +</Para> +</ListItem> +<ListItem> + +<Para> +To avoid name clashes, identifiers starting with <Literal>Hs</Literal> and +macros starting with <Literal>HS_</Literal> are reserved for the FFI. +</Para> +</ListItem> +<ListItem> + +<Para> +<Emphasis>GHC only:</Emphasis> The GHC specific types <Literal>ByteArray</Literal> and +<Literal>MutableByteArray</Literal> both map to <Literal>char*</Literal>. +</Para> +</ListItem> + +</OrderedList> + +</Para> + +</Sect2> + +<Sect2 id="sec-prim-remarks"> +<Title>Some <Literal>foreign import</Literal> wrinkles +</Title> + +<Para> + +<ItemizedList> +<ListItem> + +<Para> +By default, a <Literal>foreign import</Literal> function is <Emphasis>safe</Emphasis>. A safe +external function may cause a Haskell garbage collection as a result +of being called. This will typically happen when the imported +function end up calling Haskell functions that reside in the same +'Haskell world' (i.e., shares the same storage manager heap) -- see +Section <XRef LinkEnd="sec-entry"> for +details of how the FFI let's you call Haskell functions from the outside. + +If the programmer can guarantee that the imported function won't +call back into Haskell, the <Literal>foreign import</Literal> can be marked as +'unsafe' (see Section <XRef LinkEnd="sec-primitive"> for details of +how to do this.) + +Unsafe calls are cheaper than safe ones, so distinguishing the two +classes of external calls may be worth your while if you're extra +conscious about performance. + +</Para> +</ListItem> +<ListItem> + +<Para> +A <Literal>foreign import</Literal>ed function should clearly not need to know that +it is being called from Haskell. One consequence of this is that the +lifetimes of the arguments that are passed from Haskell <Emphasis>must</Emphasis> +equal that of a normal C call. For instance, for the following decl, + + +<ProgramListing> +foreign import "mumble" mumble :: ForeignObj -> IO () + +f :: Addr -> IO () +f ptr = do + fo <- makeForeignObj ptr myFinalizer + mumble fo +</ProgramListing> + + +The <Literal>ForeignObj</Literal> must live across the call to <Function>mumble</Function> even if +it is not subsequently used/reachable. Why the insistence on this? +Consider what happens if <Function>mumble</Function> calls a function which calls back +into the Haskell world to execute a function, behind our back as it +were. This evaluation may possibly cause a garbage collection, with +the result that <Literal>fo</Literal> may end up being finalised. + +By guaranteeing that <Literal>fo</Literal> will be considered live across the call +to <Function>mumble</Function>, the unfortunate situation where <Literal>fo</Literal> is finalised +(and hence the reference passed to <Function>mumble</Function> is suddenly no longer +valid) is avoided. + + +</Para> +</ListItem> + +</ItemizedList> + +</Para> + +</Sect2> + +</Sect1> + +<Sect1 id="sec-prim-dynamic"> +<Title>Invoking external functions via a pointer +</Title> + +<Para> +A <Literal>foreign import</Literal> declaration imports an external +function into Haskell. (The name of the external function +is statically known, but the loading/linking of it may very well +be delayed until run-time.) A <Literal>foreign import</Literal> declaration is then +(approximately) just a type cast of an external function with a +<Emphasis>statically known name</Emphasis>. +</Para> + +<Para> +An extension of <Literal>foreign import</Literal> is the support for <Emphasis>dynamic</Emphasis> type +casts of external names/addresses: +</Para> + +<Para> + +<ProgramListing> +topdecl + : ... + .. + | 'foreign' 'import' [callconv] 'dynamic' ['unsafe'] + varid :: Addr -> (prim_args -> IO prim_result) +</ProgramListing> + +</Para> + +<Para> +i.e., identical to a <Literal>foreign import</Literal> declaration, but for the +specification of <Literal>dynamic</Literal> instead of the name of an external +function. The presence of <Literal>dynamic</Literal> indicates that when an +application of <Literal>varid</Literal> is evaluated, the function pointed to by its +first argument will be invoked, passing it the rest of <Literal>varid</Literal>'s +arguments. +</Para> + +<Para> +What are the uses of this? Native invocation of COM methods, +<Footnote> +<Para> +Or the interfacing to any other software component technologies. +</Para> +</Footnote> +Haskell libraries that want to be dressed up as C libs (and hence may have +to support C callbacks), Haskell code that need to dynamically load +and execute code. +</Para> + +</Sect1> + +<Sect1 id="sec-entry"> +<Title>Exposing Haskell functions +</Title> + +<Para> +So far we've provided the Haskell programmer with ways of importing +external functions into the Haskell world. The other half of the FFI +coin is how to expose Haskell functionality to the outside world. So, +dual to the <Literal>foreign import</Literal> declaration is <Literal>foreign export</Literal>: +</Para> + +<Para> + +<ProgramListing> +topdecl + : ... + .. + | 'foreign' 'export' callconv [ext_name] varid :: prim_type +</ProgramListing> + +</Para> + +<Para> +A <Literal>foreign export</Literal> declaration tells the compiler to expose a +locally defined Haskell function to the outside world, i.e., wrap +it up behind a calling interface that's useable from C. It is only +permitted at the toplevel, where you have to specify the type at +which you want to export the function, along with the calling +convention to use. For instance, the following export declaration: +</Para> + +<Para> + +<ProgramListing> +foreign export ccall "foo" bar :: Int -> Addr -> IO Double +</ProgramListing> + +</Para> + +<Para> +will cause a Haskell system to generate the following C callable +function: +</Para> + +<Para> + +<ProgramListing> +HsDouble foo(HsInt arg1, HsAddr arg2); +</ProgramListing> + +</Para> + +<Para> +When invoked, it will call the Haskell function <Function>bar</Function>, passing +it the two arguments that was passed to <Function>foo()</Function>. +</Para> + +<Para> + +<ItemizedList> +<ListItem> + +<Para> +The range of types that can be passed as arguments and results +is restricted, since <Literal>varid</Literal> has got a <Literal>prim_type</Literal>. +</Para> +</ListItem> +<ListItem> + +<Para> +It is not possible to directly export operator symbols. +</Para> +</ListItem> +<ListItem> + +<Para> +The type checker will verify that the type given for the +<Literal>foreign export</Literal> declaration is compatible with the type given to +function definition itself. The type in the <Literal>foreign export</Literal> may +be less general than that of the function itself. For example, +this is legal: + + +<ProgramListing> + f :: Num a => a -> a + foreign export ccall "fInt" f :: Int -> Int + foreign export ccall "fFloat" f :: Float -> Float +</ProgramListing> + + +These declarations export two C-callable procedures <Literal>fInt</Literal> and +<Literal>fFloat</Literal>, both of which are implemented by the (overloaded) +Haskell function <Function>f</Function>. + +</Para> +</ListItem> +<ListItem> + +<Para> +The <Literal>foreign export</Literal>ed IO action must catch all exceptions, as +the FFI does not address how to signal Haskell exceptions to the +outside world. +</Para> +</ListItem> + +</ItemizedList> + +</Para> + +<Sect2 id="sec-callback"> +<Title>Exposing Haskell function values +</Title> + +<Para> +The <Literal>foreign export</Literal> declaration gives the C programmer access to +statically defined Haskell functions. It does not allow you to +conveniently expose dynamically-created Haskell function values as C +function pointers though. To permit this, the FFI supports +<Emphasis>dynamic</Emphasis> <Literal>foreign export</Literal>s: +</Para> + +<Para> + +<ProgramListing> +topdecl + : ... + .. + | 'foreign' 'export' [callconv] 'dynamic' varid :: prim_type -> IO Addr +</ProgramListing> + +</Para> + +<Para> +A <Literal>foreign export dynamic</Literal> declaration declares a C function +pointer <Emphasis>generator</Emphasis>. Given a Haskell function value of some restricted +type, the generator wraps it up behind an externally callable interface, +returning an <Literal>Addr</Literal> to an externally callable (C) function pointer. +</Para> + +<Para> +When that function pointer is eventually called, the corresponding +Haskell function value is applied to the function pointer's arguments +and evaluated, returning the result (if any) back to the caller. +</Para> + +<Para> +The mapping between the argument to a <Literal>foreign export dynamic</Literal> +declaration and its corresponding C function pointer type, is as +follows: +</Para> + +<Para> + +<ProgramListing> +typedef cType[[Res]] (*Varid_FunPtr) + (cType[[Ty_1]] ,.., cType[[Ty_n]]); +</ProgramListing> + +</Para> + +<Para> +where <Literal>cType[[]]</Literal> is the Haskell to C type mapping presented +in Section <XRef LinkEnd="sec-mapping">. +</Para> + +<Para> +To make it all a bit more concrete, here's an example: +</Para> + +<Para> + +<ProgramListing> +foreign export dynamic mkCallback :: (Int -> IO Int) -> IO Addr + +foreign import registerCallback :: Addr -> IO () + +exportCallback :: (Int -> IO Int) -> IO () +exportCallback f = do + fx <- mkCallback f + registerCallback fx +</ProgramListing> + +</Para> + +<Para> +The <Literal>exportCallback</Literal> lets you register a Haskell function value as +a callback function to some external library. The C type of the +callback that the external library expects in <Literal>registerCallback()</Literal>, +is: +<Footnote> +<Para> +An FFI implementation is encouraged to generate the C typedef corresponding +to a <Literal>foreign export dynamic</Literal> declaration, but isn't required +to do so. +</Para> +</Footnote> + +</Para> + +<Para> + +<ProgramListing> +typedef HsInt (*mkCallback_FunPtr) (HsInt arg1); +</ProgramListing> + +</Para> + +<Para> +Creating the view of a Haskell closure as a C function pointer entails +registering the Haskell closure as a 'root' with the underlying +Haskell storage system, so that it won't be garbage collected. The FFI +implementation takes care of this, but when the outside world is +through with using a C function pointer generated by a <Literal>foreign +export dynamic</Literal> declaration, it needs to be explicitly freed. This is +done by calling: +</Para> + +<Para> + +<ProgramListing> +void freeHaskellFunctionPtr(void *ptr); +</ProgramListing> + +</Para> + +<Para> +In the event you need to free these function pointers from within +Haskell, a standard 'foreign import'ed binding of the above C entry +point is also provided, +</Para> + +<Para> + +<ProgramListing> +Foreign.freeHaskellFunctionPtr :: Addr -> IO () +</ProgramListing> + +</Para> + +</Sect2> + +<Sect2 id="sec-foreign-label"> +<Title>Code addresses +</Title> + +<Para> +The <Literal>foreign import</Literal> declaration allows us to invoke an external +function by name from within the comforts of the Haskell world, while +<Literal>foreign import dynamic</Literal> lets us invoke an external function by +address. However, there's no way of getting at the code address of +some particular external label though, which is at times useful, +e.g. for the construction of method tables for, say, Haskell COM +components. To support this, the FFI has got <Literal>foreign label</Literal>s: +</Para> + +<Para> + +<ProgramListing> +foreign label "freeAtLast" addrOf_freeAtLast :: Addr +</ProgramListing> + +</Para> + +<Para> +The meaning of this declaration is that <Literal>addrOf_freeAtLast</Literal> will now +contain the address of the label <Literal>freeAtLast</Literal>. +</Para> + +</Sect2> + +</Sect1> + +<Sect1 id="sec-changelog"> +<Title>Change history +</Title> + +<Para> + +<ItemizedList> +<ListItem> + +<Para> +0.95 --> 0.96: + +<ItemizedList> +<ListItem> + +<Para> +changed the C representation of <Literal>Haskell_ForeignObj</Literal> from +<Literal>(long*)</Literal> to <Literal>(void*)</Literal> -- ANSI C guarantees that <Literal>(void*)</Literal> +is the widest possible data pointer. +</Para> +</ListItem> +<ListItem> + +<Para> +Updated defnition of <Literal>varid</Literal> in Section +<XRef LinkEnd="sec-prim-name"> to reflect Haskell98's. +</Para> +</ListItem> +<ListItem> + +<Para> +Replaced confusing uses of <Literal>stdcall</Literal> with <Literal>ccall</Literal>. +</Para> +</ListItem> + +</ItemizedList> + +</Para> +</ListItem> +<ListItem> + +<Para> +0.96 --> 0.97: + +<ItemizedList> +<ListItem> + +<Para> +Simplified the calling convention section, support for Pascal (and +fastcall) calling conventions dropped. +</Para> +</ListItem> +<ListItem> + +<Para> +Clarified that the arguments to a safe <Literal>foreign import</Literal> must have +lifetimes that equal that of a C function application. +</Para> +</ListItem> +<ListItem> + +<Para> +Outlawed the use of the (GHC specific) types <Literal>ByteArray</Literal> +and <Literal>MutableByteArray</Literal> in safe <Literal>foreign import</Literal>s. +</Para> +</ListItem> +<ListItem> + +<Para> +Added a note that support for the use of unboxed types in +<Literal>foreign import</Literal> may be withdrawn/deprecated sometime in the future. +</Para> +</ListItem> +<ListItem> + +<Para> +Simplified section which sketches a possible implementation. +</Para> +</ListItem> +<ListItem> + +<Para> +Use <Literal>Hs</Literal> as prefix for the typedefs for the primitive Haskell +FFI types rather than the longer <Literal>Haskell_</Literal>. +</Para> +</ListItem> + +</ItemizedList> + +</Para> +</ListItem> +<ListItem> + +<Para> +0.97 --> 0.98: + +<ItemizedList> +<ListItem> + +<Para> +Leave out implementation section; of limited interest. +</Para> +</ListItem> +<ListItem> + +<Para> +Outlined the criteria used to decide on what calling +conventions to support. +</Para> +</ListItem> +<ListItem> + +<Para> +Include <Literal>newtype</Literal>s that wrap primitive types in the list +of types that can be both passed to and returned from external +functions. +</Para> +</ListItem> + +</ItemizedList> + +</Para> +</ListItem> +<ListItem> + +<Para> +0.98 --> 0.99: + +<ItemizedList> +<ListItem> + +<Para> +Updated the section on type mapping to integrate some comments +from people on <ffi@haskell.org> (a fair chunk of the text +in that section was contributed by Sven Panne.) +</Para> +</ListItem> +<ListItem> + +<Para> +<Function>freeHaskellFunctionPtr</Function> should belong to module <Literal>Foreign</Literal>, not <Literal>IOExts</Literal>. +</Para> +</ListItem> + +</ItemizedList> + + +</Para> +</ListItem> +<ListItem> + +<Para> +0.99 --> 0.99.1: + +<ItemizedList> +<ListItem> + +<Para> +<Literal>Bool</Literal> is now an FFI-supported type (i.e., added it to +<Literal>ext_ty</Literal>.) +</Para> +</ListItem> + +</ItemizedList> + + +</Para> +</ListItem> + +</ItemizedList> + +</Para> + +</Sect1> + +</Article> -- GitLab