Niffler.Library behaviour (Niffler v0.3.0) View Source
Niffler.Library
allows to wrap dynamically loaded libraries. And create foreign
function interfaces (FFI) for them. This usually requires:
- Shared headers such for type definitions
- Some init code involving
dlopen()
- Static variables/state that is part of the library
- Potential deinit code involving
dlclose()
Niffler.Library
allows to produce modules at runtime doing all these
things and exposing access to the c-functions of a dynamic library.
defmodule Gmp do
use Niffler.Library, thread_safe: false
@impl true
def header() do
"""
// library handle
void *gmp;
// types
typedef struct
{
int _mp_alloc;
int _mp_size;
void *_mp_d;
} __mpz_struct;
typedef __mpz_struct mpz_t[1];
void (*mpz_init)(mpz_t);
// ...
"""
end
@impl true
def on_load() do
"""
// loading the library with dlopen()
gmp = dlopen("libgmp.#{library_suffix()}", RTLD_LAZY);
if (!gmp) {
return "could not load libgmp";
}
// loading symbols:
dlerror();
if (!(mpz_init = dlsym(gmp, "__gmpz_init"))) {
return dlerror();
}
// other symbols ...
"""
end
@impl true
def on_destroy() do
"""
if (!gmp) {
return;
}
// unloading
dlclose(gmp);
"""
end
# definining one or more operations here...
defnif :mul, [a: :int, b: :int], ret: :int do
"""
mpz_set_si(ma, $a);
mpz_set_si(mb, $b);
mpz_mul(mc, ma, mb);
$ret = mpz_get_si(mc);
"""
end
end
Once defined the module functions can be used via:
{ok, [result]} = Gmp.mul(4, 5)
Link to this section Summary
Functions
Defines a new nif function in the current module.
Returns the current platforms default library suffix
Callbacks
Return a c-fragement of a common header for type definitions, static variables and other neccesary c code.
Return a c-fragement that is called when the module is unloaded.
Typicallly this fragment would contain a call to dlclose()
for
a dynamic library.
Return a c-fragement that is called on the first call to the module.
Typicall this fragment would contain a call to dlopen()
when loading
a dynamic library.
Link to this section Functions
Specs
defnif(atom(), keyword(), keyword(), [{:do, binary()}]) :: {:__block__, [], [{any(), any(), any()}, ...]}
Defines a new nif function in the current module.
Same as Niffler.defnif/4
but with access to the current module context.
Returns the current platforms default library suffix:
dll
on windowsdylib
on macso
on linux
Useful for dlopen() code to load the correct library:
@impl true
def on_load() do
"""
// loading the library with dlopen()
gmp = dlopen("libgmp.#{library_suffix()}", RTLD_LAZY);
if (!gmp) {
return "could not load libgmp";
}
"""
end
Link to this section Callbacks
Specs
header() :: binary()
Return a c-fragement of a common header for type definitions, static variables and other neccesary c code.
Example:
@impl true
def header() do
"""
// library handle
void *gmp;
"""
end
Specs
on_destroy() :: binary()
Return a c-fragement that is called when the module is unloaded.
Typicallly this fragment would contain a call to dlclose()
for
a dynamic library.
Example:
@impl true
def on_destroy() do
"""
if (!gmp) {
return;
}
// unloading
dlclose(gmp);
"""
end
Specs
on_load() :: binary()
Return a c-fragement that is called on the first call to the module.
Typicall this fragment would contain a call to dlopen()
when loading
a dynamic library.
This c-fragment should return a char* (a common string in c) when any error has occured.
Example:
@impl true
def on_load() do
"""
// loading the library with dlopen()
gmp = dlopen("libgmp.#{library_suffix()}", RTLD_LAZY);
if (!gmp) {
return "could not load libgmp";
}
"""
end