Поиск…


Определение

Официальная документация: http://erlang.org/doc/tutorial/nif.html

NIF были введены в Erlang / OTP R13B03 в качестве экспериментальной функции. Цель состоит в том, чтобы разрешить вызов C-кода из кода Erlang.

NIF реализованы в C вместо Erlang, но они отображаются как любые другие функции в области кода Erlang, поскольку они принадлежат модулю, в котором произошло включение. Библиотеки NIF связаны с компиляцией и загружаются во время выполнения.

Поскольку библиотеки NIF динамически связаны с процессом эмулятора, они бывают быстрыми, но также и опасными, потому что сбой в NIF также приводит к тому, что эмулятор тоже работает.

Пример: текущее время UNIX

Вот очень простой пример, иллюстрирующий, как писать NIF.

Структура каталога:

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

Эту структуру можно легко инициализировать с помощью Rebar3:

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

Содержание 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);

Содержание 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).

Содержимое 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"}
]}.

Теперь вы можете запустить пример:

$ 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> 

API Erlang C (от C до Erlang)

Официальная документация : http://erlang.org/doc/man/erl_nif.html

Наиболее важными структурами, типами и макросами API Erlang C являются:

  • ERL_NIF_TERM : тип для терминов Erlang. Это тип возвращаемого значения, которому должны следовать функции NIF.
  • ERL_NIF_INIT(MODULE, ErlNifFunc funcs[], load, reload, upgrade, unload) : Это макрос, который фактически создает NIF, определенные в определенном файле C. Он должен оцениваться в глобальном масштабе. Обычно это будет последняя строка в файле C.
  • ErlNifFunc : тип, с которым каждый NIF передается в ERL_NIF_INIT для экспорта. Эта структура состоит из имени, arity, poiter для функции C и флагов. Массив этого типа со всеми определениями NIF должен быть создан для передачи в ERL_NIF_INIT .
  • ErlNifEnv : среда Erlang, в которой выполняется NIF. Обязательно передать среду в качестве первого аргумента для каждого NIF. Этот тип непрозрачен и может управляться только с помощью функций, которые предлагает API Erlang C.


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow