Zoeken…


Definitie

Officiële documentatie: http://erlang.org/doc/tutorial/nif.html

NIF's werden geïntroduceerd in Erlang / OTP R13B03 als een experimentele functie. Het doel is om C-code vanuit Erlang-code aan te roepen.

NIF's zijn geïmplementeerd in C in plaats van Erlang, maar ze verschijnen als alle andere functies in het bereik van Erlang-code omdat ze behoren tot de module waar de opname is gebeurd. NIF-bibliotheken worden tijdens het compileren gekoppeld en tijdens runtime geladen.

Omdat NIF-bibliotheken dynamisch zijn gekoppeld aan het emulatorproces, zijn ze snel, maar ook gevaarlijk, omdat crashen in een NIF de emulator ook naar beneden haalt.

Voorbeeld: huidige UNIX-tijd

Hier is een heel eenvoudig voorbeeld om te illustreren hoe een NIF te schrijven.

Directory structuur:

nif_test
├── c_src
│   ├── Makefile
│   └── nif_test.c
├── rebar.config
└── src
    ├── nif_test.app.src
    └── nif_test.erl

Deze structuur kan eenvoudig worden geïnitialiseerd met behulp van Rebar3:

$ rebar3 new lib nif_test && cd nif_test && rebar3 new cmake

Inhoud van 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);

Inhoud van 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).

Inhoud van 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"}
]}.

Nu kunt u het voorbeeld uitvoeren:

$ 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 tot Erlang)

Officiële documentatie : http://erlang.org/doc/man/erl_nif.html

De belangrijkste structuren, typen en macro's van de Erlang C API zijn de volgende:

  • ERL_NIF_TERM : het type voor Erlang-termen. Dit is het retourtype dat NIF-functies moeten volgen.
  • ERL_NIF_INIT(MODULE, ErlNifFunc funcs[], load, reload, upgrade, unload) : dit is de macro die in feite de NIF's maakt die in een bepaald C-bestand zijn gedefinieerd. Het moet worden geëvalueerd in de wereldwijde scope. Normaal gesproken is dit de laatste regel in het C-bestand.
  • ErlNifFunc : het type waarmee elke NIF wordt doorgegeven aan ERL_NIF_INIT om te worden geëxporteerd. Deze structuur bestaat uit naam, arity, een poiter voor de C-functie en vlaggen. Een array van dit type met alle NIF-definities moet worden gemaakt om te worden doorgegeven aan ERL_NIF_INIT .
  • ErlNifEnv : de Erlang-omgeving waar de NIF wordt uitgevoerd. Het is verplicht om de omgeving door te geven als het eerste argument voor elke NIF. Dit type is ondoorzichtig en kan alleen worden gemanipuleerd met behulp van de functies die de Erlang C API biedt.


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow