Exploring libffi with NekoVM

As a short proof of concept started in on nekoffi. Integrating NekoVM with libffi.

This example doesn’t gain much over the normal NekoVM builtin C FFI, but pass 2 will include dynamic symbol lookup, which should mean a single $loader.loadprim per Neko source to get at just about any and all C library functions.

The tl;dr; Using NekoVM C-FFI integrated with libffi will mean Neko programmers will not have to write any C wrappers to allow primitive access to C functions.

What follows is baby step 1, to make sure things don’t jump and catch fire.

nekoffi.c

/*
  Author: Brian Tiffin
  Dedicated to the public domain

  Date started: October 2018
  Modified: 2018-10-23/22:30-0400 btiffin

  Tectonics:
    gcc -shared -fPIC -o nekoffi.ndll nekoffi.c -lffi
*/

/* NekoVM with libffi */
#include <stdio.h>
#include <neko.h>
#include <ffi.h>

value
ffi(value message)
{
    ffi_cif cif;
    ffi_type *args[1];
    void *values[1];
    char *s;
    ffi_arg rc;

    args[0] = &ffi_type_pointer;
    values[0] = &s;

    if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_sint, args) == FFI_OK) {
        s = val_string(message);
        ffi_call(&cif, puts, &rc, values);
    }

    return alloc_int(rc);
}
DEFINE_PRIM(ffi, 1);

nekoffi.neko

/**
 libffi integration with Neko
*/

var ffi = $loader.loadprim("nekoffi@ffi", 1);
ffi("Hello, ffi");
ffi("Hello, again ffi");

(GNU) make rules:

.RECIPEPREFIX = >

# NekoVM with libffi
nekoffi.ndll: nekoffi.c
> gcc -shared -fPIC -o nekoffi.ndll nekoffi.c -lffi

nekoffi: nekoffi.neko
> nekoc nekoffi.neko
> nekotools boot nekoffi.n

And a sample run:

prompt$ make nekoffi
gcc -w -shared -fPIC -o nekoffi.ndll nekoffi.c -lffi
nekoc nekoffi.neko
nekotools boot nekoffi.n

prompt$ ./nekoffi
Hello, ffi
Hello, again ffi

Calling puts via libffi from a Neko string.

Note: Don’t do this at home (just yet). -w turns off a warning about incompatible pointer types which is just noise for the phase 1 trial (but will be fixed in phase 2).

Anyway, it works. So on to step 2.

In the trial, puts is hardcoded. That will change on phase 2 to a Neko interface of

ffi("C-Function", RETURN-TYPE, args...)

LoadLibrary/dlopen dlsym will be used to get the actual function pointer for use with libffi in the next cut.

Similar to the design used with uniffi, a Unicon version of a similar code sequence, there are wrinkles to overcome. The types may require overrides. Neko float values (which are C double), might need to be cast to an actual C float type. Neko int may need to be cast to C short, etc. Instead of requiring each and every argument of an ffi call to be explicitly typed, a simple pair can be passed with an override type when required. I hope, not there yet, but it’ll be a design goal.

libffi or GitHub - libffi/libffi: A portable foreign-function interface library.

For a more complete view on how this might shake out if step 2 succeeds see: Multilanguage — Unicon Programming v0.6.148

Have good, make well