如果我自己编写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"}]}.
test.erl
:
-module(test).
-export([main/1]).
main(_Args) ->
jiffy:decode(<<"1">>),
ok.
rebar get-deps编译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
有没有办法克服这个问题?
答案 0 :(得分: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).
这可以很容易地扩展到循环搜索路径以查找文件。请注意,NIF_DIR
不是一个特殊名称,只是我“发明”的名称。
答案 1 :(得分:1)
似乎无法从escript加载nif,因为erlang:load_nif
不会查看存档。这是因为大多数操作系统都需要可以映射到内存的*.so
的物理副本。
解决此问题的最佳方法是将* .so文件复制到escript的输出目录中。
{ok, _Bytes} = file:copy("deps/jiffy/priv/jiffy.so", "bin/jiffy.so"),
查看edis
的{{3}}。您将看到这是他们如何从escript加载eleveldb的nif执行。