erlang rebar escriptize&nifs

cas*_*ere 10 erlang rebar erlang-nif

如果我自己编写escript,我可以使用nif,但是当我使用rebar escriptize时,无法找到nif函数.我认为这是因为*.so对象没有像束文件那样被打包.这是一个简单的例子;

rebar.config:

{deps, [
   {'jiffy', "", {git, "https://github.com/davisp/jiffy.git", {branch, master}}}
]}.
{escript_incl_apps, [jiffy]}.
%% I tried this to see what happens if the so got in there but didn't help
{escript_incl_extra, [{"deps/jiffy/priv/jiffy.so", "/path/to/my/proj"}]}.
Run Code Online (Sandbox Code Playgroud)

test.erl:

-module(test).

-export([main/1]).

main(_Args) ->
    jiffy:decode(<<"1">>),
    ok.
Run Code Online (Sandbox Code Playgroud)


rebar get-deps compile escriptize ./test

结果是

escript: exception error: undefined function jiffy:decode/1
  in function  test:main/1 (src/test.erl, line 7)
  in call from escript:run/2 (escript.erl, line 741)
  in call from escript:start/1 (escript.erl, line 277)
  in call from init:start_it/1
  in call from init:start_em/1
Run Code Online (Sandbox Code Playgroud)

有办法克服这个问题吗?

rvi*_*ing 3

问题在于该erlang:load_nif/1函数不会式使用任何搜索路径,也不会在尝试查找.so文件时执行任何智能操作。它只是尝试按文件名参数给出的字面意思加载文件。如果它不是绝对文件名,那么它将尝试加载相对于当前工作目录的文件。它会准确地加载您告诉它加载的内容。

因此,如果您调用erlang:load_nif("jiffy.so"),它将尝试从您当前的工作目录加载"jiffy.so"。我使用的一个简单的解决方法是使用NIF_DIR环境变量执行类似的操作:

load_nifs() ->
    case os:getenv("NIF_DIR") of
        false -> Path = ".";
        Path -> Path
    end,
    ok = erlang:load_nif(Path ++ "/gpio_nifs", 0).
Run Code Online (Sandbox Code Playgroud)

这可以轻松扩展以循环搜索路径来查找文件。请注意,这NIF_DIR不是一个特殊的名称,只是我“发明”的一个名称。