Erlang Language
NIFs
Suche…
Definition
Offizielle Dokumentation: http://erlang.org/doc/tutorial/nif.html
NIFs wurden als experimentelles Feature in Erlang / OTP R13B03 eingeführt. Der Zweck besteht darin, den Aufruf von C-Code innerhalb des Erlang-Codes zuzulassen.
NIFs werden in C anstelle von Erlang implementiert. Sie erscheinen jedoch als beliebige andere Funktionen im Erlang-Code, da sie zu dem Modul gehören, in dem das Include enthalten ist. NIF-Bibliotheken werden beim Kompilieren verknüpft und zur Laufzeit geladen.
Da NIF-Bibliotheken dynamisch in den Emulatorprozess eingebunden werden, sind sie schnell, aber auch gefährlich, da ein Absturz in einem NIF den Emulator ebenfalls zum Erliegen bringt.
Beispiel: aktuelle UNIX-Zeit
Hier ist ein sehr einfaches Beispiel, um zu zeigen, wie man eine NIF schreibt.
Verzeichnisaufbau:
nif_test
├── c_src
│ ├── Makefile
│ └── nif_test.c
├── rebar.config
└── src
├── nif_test.app.src
└── nif_test.erl
Diese Struktur kann einfach mit Rebar3 initialisiert werden:
$ rebar3 new lib nif_test && cd nif_test && rebar3 new cmake
Inhalt von 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);
Inhalt von 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).
Inhalt von 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"}
]}.
Nun können Sie das Beispiel ausführen:
$ 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 bis Erlang)
Offizielle Dokumentation : http://erlang.org/doc/man/erl_nif.html
Die wichtigsten Strukturen, Typen und Makros der Erlang C-API sind folgende:
-
ERL_NIF_TERM
: der Typ für Erlang-Ausdrücke. Dies ist der Rückgabetyp, dem NIF-Funktionen folgen müssen. -
ERL_NIF_INIT(MODULE, ErlNifFunc funcs[], load, reload, upgrade, unload)
: Dies ist das Makro, das die in einer bestimmten C-Datei definierten NIFs erstellt. Es muss im globalen Bereich ausgewertet werden. Normalerweise ist dies die letzte Zeile in der C-Datei. -
ErlNifFunc
: Der Typ, mit dem jede NIF zumERL_NIF_INIT
anERL_NIF_INIT
. Diese Struktur besteht aus Name, Arity, einem Poiter für die C-Funktion und Flags. Ein Array dieses Typs mit allen NIF-Definitionen sollte erstellt werden, um anERL_NIF_INIT
übergeben zuERL_NIF_INIT
. -
ErlNifEnv
: Die Erlang-Umgebung, in der die NIF ausgeführt wird. Es ist zwingend erforderlich, die Umgebung als erstes Argument für jede NIF zu übergeben. Dieser Typ ist undurchsichtig und kann nur mit den Funktionen der Erlang C-API bearbeitet werden.