Erlang Language
NIFs
Recherche…
Définition
Documentation officielle: http://erlang.org/doc/tutorial/nif.html
Les NIF ont été introduits dans Erlang / OTP R13B03 en tant que fonctionnalité expérimentale. Le but est d’appeler le code C depuis le code Erlang.
Les NIF sont implémentés dans C au lieu d'Erlang, mais ils apparaissent comme toutes les autres fonctions dans le cadre du code Erlang, car ils appartiennent au module où l'inclusion s'est produite. Les bibliothèques NIF sont liées à la compilation et chargées à l'exécution.
Les bibliothèques NIF étant liées dynamiquement au processus de l'émulateur, elles sont rapides, mais également dangereuses, car les pannes dans un fichier NIF entraînent également la perte de l'émulateur.
Exemple: heure UNIX actuelle
Voici un exemple très simple pour illustrer comment écrire un NIF.
Structure du répertoire:
nif_test
├── c_src
│ ├── Makefile
│ └── nif_test.c
├── rebar.config
└── src
├── nif_test.app.src
└── nif_test.erl
Cette structure peut être facilement initialisée avec Rebar3:
$ rebar3 new lib nif_test && cd nif_test && rebar3 new cmake
Contenu 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);
Contenu 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).
Contenu 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"}
]}.
Maintenant, vous pouvez exécuter l'exemple:
$ 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 à Erlang)
Documentation officielle : http://erlang.org/doc/man/erl_nif.html
Les structures, types et macros les plus importants de l'API Erlang C sont les suivants:
-
ERL_NIF_TERM
: le type des termes Erlang. C'est le type de retour que les fonctions NIF doivent suivre. -
ERL_NIF_INIT(MODULE, ErlNifFunc funcs[], load, reload, upgrade, unload)
: C'est la macro qui crée réellement les NIF définis dans un certain fichier C. Il doit être évalué dans son ensemble. Normalement, ce sera la dernière ligne du fichier C. -
ErlNifFunc
: le type avec lequel chaque NIF est passé àERL_NIF_INIT
pour être exporté. Cette structure est composée de name, arity, d'un poiter à la fonction C et de flags. Un tableau de ce type avec toutes les définitions NIF doit être créé pour être transmis àERL_NIF_INIT
. -
ErlNifEnv
: l'environnement Erlang dans lequel le NIF est exécuté. Il est obligatoire de passer l'environnement comme premier argument pour chaque NIF. Ce type est opaque et ne peut être manipulé qu'à l'aide des fonctions offertes par l'API Erlang C.