.so
files on Linux, .dylib
files on macOS and .dll
on Windows. Luna is able to work with object files coming from two sources: 1. System-wide available dynamic libraries. If a library is installed on your machine, Luna will be able to use it. Unfortunately, this requires all the users of your library to have the dynamic library installed in their systems. For most libraries this is not a good solution, it will, however, work fine for bindings to the most popular libraries and for quick prototyping. 2. Object files inside the project tree. You can drop any shared object file into the native_libs/PLATFORM
directory inside your project (PLATFORM
is macos
, linux
or windows
) and use it from Luna. This is a great solution for making sure users are able to use your library without any external dependencies. It's also the only way to include your own C extension or wrapper.[info] Changes ahead!This describes the bare-bones way of interacting with foreign objects. There are some syntactic changes coming soon to cut down on boilerplate. The basic concepts, however, will remain unchanged.
lookupSymbol
function from Std.Foreign
module. It takes a shared object file name and a name of the symbol to lookup, and returns a FunPtr
object. The library resolution takes into account the most common naming conventions, so that it is possible to use the same call with a file named awesome.dylib
as well as libawesome.4.so
. So, in our example, you can just write:call
method of FunPtr
does. It takes two arguments – a representation for the output type and a list of objects of type CArg
, representing the function arguments. Note that not every type can be represented as a C argument. The types that can (numeric types, pointers and a few more) are converted using their toCArg
method. So, back to our example. The awesomeFunction
expects and int
and returns an int
. Note that Luna's Int
s are different from C's, so the latter are represented by the class CInt
. This is what our function call looks like:CInt
. Most Luna programs, however, use standard Int
s and these cannot easily be represented in C. This can be fixed with the help of CInt.fromInt
function, which converts an ordinary Int
object into a CInt
. It also returns a CInt
, which again is not very handy. This can be fixed with the help of toInt
method of CInt
. The final version of our wrapper, which operates on Int
s and from the outside is nearly indistinguishable from pure Luna code looks like this:Std.Foreign.C.Value
module. This section is a short overview of all of them.fromInt
and toInt
methods, support comparison and basic arithmetic operators. The following table shows the C types and their Luna counterparts.CDouble
and CFloat
classes as counterparts of C's double
and float
, respectively. Both classes define fromReal
and toReal
methods for conversion between them and Luna's Real
. They also support basic arithmetic and comparison operators.Pointer
. It takes a single argument denoting the type of its content. So, for example, Pointer CInt
corresponds to int*
in C, while Pointer (Pointer None)
is void**
.X
use the malloc
method on pointer class:X
object must define a byteSize
method, returning the size in bytes of the structure. You can also use mallocElems
to create arrays like so:free
method – if you're done with your ptr
just call ptr.free
.read
method. It works on a Ptr X
and returns a value of type X
. Keep in mind that in order for this to work, the X
type must define a readPtr
method that takes a bare pointer and plucks the fields one by one.ptr
of type Pointer X
, call ptr.write x
. Again, this requires the type X
to define writePtr
method.ptr.moveBytes i
method – it returns a new pointer, resulting from adding i
bytes to ptr
. There is also a moveElems
method, that will move the pointer by the specified number of elements (i.e. by number of elements * element.byteSize
bytes).X
type call, like for pointer, malloc
method just on the managed pointer class:mallocElems
works just like for regular poinetrs. To create array with managed pointer use:ptr
. For this finalizer function fin
is required. Finalizer will be run when the pointer will be garbage collected:read
, write
, moveElems
works the same way for managed pointers like for regular pointers.SHA1
function from openssl
. It takes an input buffer of type unsigned char*
, a size_t
denoting the length of input and an output buffer of type unsigned char*
and length 20. Suppose you have a list of Luna Int
s and want to compute the SHA1 digest of this list, as another list of Int
s. This is how this can be done with Luna's FFI: