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 zum ERL_NIF_INIT an ERL_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 an ERL_NIF_INIT übergeben zu ERL_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.


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow