Erlang Language
NIF
Ricerca…
Definizione
Documentazione ufficiale: http://erlang.org/doc/tutorial/nif.html
I NIF sono stati introdotti in Erlang / OTP R13B03 come funzione sperimentale. Lo scopo è quello di consentire di chiamare il codice C all'interno del codice Erlang.
I NIF sono implementati in C anziché in Erlang, ma appaiono come qualsiasi altra funzione nell'ambito del codice Erlang in quanto appartengono al modulo in cui è avvenuta l'inclusione. Le librerie NIF sono collegate alla compilazione e caricate in runtime.
Poiché le librerie NIF sono collegate dinamicamente al processo di emulazione, sono veloci, ma anche pericolose, perché l'arresto anomalo in un NIF porta anche l'emulatore verso il basso.
Esempio: tempo UNIX corrente
Ecco un esempio molto semplice per illustrare come scrivere un NIF.
Struttura della directory:
nif_test
├── c_src
│ ├── Makefile
│ └── nif_test.c
├── rebar.config
└── src
├── nif_test.app.src
└── nif_test.erl
Questa struttura può essere facilmente inizializzata usando Rebar3:
$ rebar3 new lib nif_test && cd nif_test && rebar3 new cmake
Contenuto di nif_test.c
:
#include "erl_nif.h"
#include "time.h"
static ERL_NIF_TERM now(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
return enif_make_int(env, time(0));
}
static ErlNifFunc nif_funcs[] = {
{"now", 0, now}
};
ERL_NIF_INIT(nif_test,nif_funcs,NULL,NULL,NULL,NULL);
Contenuto di nif_test.erl
:
-module(nif_test).
-on_load(init/0).
-export([now/0]).
-define(APPNAME, nif_test).
-define(LIBNAME, nif_test).
%%====================================================================
%% API functions
%%====================================================================
now() -> nif_not_loaded.
%%====================================================================
%% Internal functions
%%====================================================================
init() ->
SoName = case code:priv_dir(?APPNAME) of
{error, bad_name} ->
case filelib:is_dir(filename:join(["..", priv])) of
true -> filename:join(["..", priv, ?LIBNAME]);
_ -> filename:join([priv, ?LIBNAME])
end;
Dir -> filename:join(Dir, ?LIBNAME)
end,
erlang:load_nif(SoName, 0).
Contenuto di rebar.config
:
{erl_opts, [debug_info]}.
{deps, []}.
{pre_hooks, [
{"(linux|darwin|solaris)", compile, "make -C c_src"},
{"(freebsd)", compile, "gmake -C c_src"}
]}.
{post_hooks, [
{"(linux|darwin|solaris)", clean, "make -C c_src clean"},
{"(freebsd)", clean, "gmake -C c_src clean"}
]}.
Ora puoi eseguire l'esempio:
$ rebar3 shell
===> Verifying dependencies...
===> Compiling nif_test
make: Entering directory '/home/vschroeder/Projects/nif_test/c_src'
cc -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes -fPIC -I /usr/local/lib/erlang/erts-7.3.1/include/ -I /usr/local/lib/erlang/lib/erl_interface-3.8.2/include -c -o /home/vschroeder/Projects/nif_test/c_src/nif_test.o /home/vschroeder/Projects/nif_test/c_src/nif_test.c
cc /home/vschroeder/Projects/nif_test/c_src/nif_test.o -shared -L /usr/local/lib/erlang/lib/erl_interface-3.8.2/lib -lerl_interface -lei -o /home/vschroeder/Projects/nif_test/c_src/../priv/nif_test.so
make: Leaving directory '/home/vschroeder/Projects/nif_test/c_src'
Erlang/OTP 18 [erts-7.3.1] [source] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V7.3.1 (abort with ^G)
1> nif_test:now().
1469732239
2> nif_test:now().
1469732264
3>
Erlang C API (C a Erlang)
Documentazione ufficiale : http://erlang.org/doc/man/erl_nif.html
Le strutture, i tipi e le macro più importanti dell'AP Erlang C sono i seguenti:
-
ERL_NIF_TERM
: il tipo per i termini di Erlang. Questo è il tipo di ritorno che le funzioni NIF devono seguire. -
ERL_NIF_INIT(MODULE, ErlNifFunc funcs[], load, reload, upgrade, unload)
: questa è la macro che crea effettivamente i NIF definiti in un determinato file C. Deve essere valutato nell'ambito globale. Normalmente sarà l'ultima riga nel file C. -
ErlNifFunc
: il tipo con cui ogni NIF viene passato aERL_NIF_INIT
per essere esportato. Questa struct è composta da nome, arity, un poiter alla funzione C e flag. Un array di questo tipo con tutte le definizioni NIF deve essere creato per essere passato aERL_NIF_INIT
. -
ErlNifEnv
: l'ambiente Erlang in cui viene eseguito il NIF. È obbligatorio passare l'ambiente come primo argomento per ogni NIF. Questo tipo è opaco e può essere manipolato solo utilizzando le funzioni che l'API di Erlang C offre.