Erlang Language
NIFs
Buscar..
Definición
Documentación oficial: http://erlang.org/doc/tutorial/nif.html
Los NIF se introdujeron en Erlang / OTP R13B03 como una característica experimental. El propósito es permitir llamar el código C desde el código de Erlang.
Los NIF se implementan en C en lugar de Erlang, pero aparecen como cualquier otra función en el alcance del código de Erlang, ya que pertenecen al módulo donde ocurrió la inclusión. Las bibliotecas NIF están vinculadas en la compilación y cargadas en tiempo de ejecución.
Debido a que las bibliotecas NIF están vinculadas dinámicamente al proceso del emulador, son rápidas, pero también peligrosas, ya que al bloquearse en un NIF también se desactiva el emulador.
Ejemplo: hora actual de UNIX
Aquí hay un ejemplo muy simple para ilustrar cómo escribir un NIF.
Estructura de directorios:
nif_test
├── c_src
│ ├── Makefile
│ └── nif_test.c
├── rebar.config
└── src
├── nif_test.app.src
└── nif_test.erl
Esta estructura se puede inicializar fácilmente usando Rebar3:
$ rebar3 new lib nif_test && cd nif_test && rebar3 new cmake
Contenido de 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);
Contenido de 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).
Contenido de 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"}
]}.
Ahora puedes ejecutar el ejemplo:
$ 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)
Documentación oficial : http://erlang.org/doc/man/erl_nif.html
Las estructuras, tipos y macros más importantes de la API de Erlang C son las siguientes:
-
ERL_NIF_TERM
: el tipo para los términos de Erlang. Este es el tipo de retorno que deben seguir las funciones NIF. -
ERL_NIF_INIT(MODULE, ErlNifFunc funcs[], load, reload, upgrade, unload)
: esta es la macro que realmente crea los NIF definidos en un determinado archivo C. Debe ser evaluado en el ámbito global. Normalmente será la última línea en el archivo C. -
ErlNifFunc
: el tipo con el cual cada NIF se pasa aERL_NIF_INIT
para ser exportado. Esta estructura se compone de un nombre, una aridad, un indicador de la función C y las banderas. Se debe crear una matriz de este tipo con todas las definiciones de NIF paraERL_NIF_INIT
aERL_NIF_INIT
. -
ErlNifEnv
: el entorno Erlang donde se ejecuta el NIF. Es obligatorio pasar el entorno como el primer argumento para cada NIF. Este tipo es opaco y solo se puede manipular utilizando las funciones que ofrece la API de Erlang C.