简体   繁体   English

erlang rebar escriptize&nifs

[英]erlang rebar escriptize & nifs

I can use nif's if I write the escript myself, however when I use rebar escriptize the nif functions cannot be found. 如果我自己编写escript,我可以使用nif,但是当我使用rebar escriptize时,无法找到nif函数。 I think it is because *.so objects are not getting packed like beam files. 我认为这是因为* .so对象没有像束文件那样被打包。 Here is an simple example; 这是一个简单的例子;

rebar.config : 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 : test.erl

-module(test).

-export([main/1]).

main(_Args) ->
    jiffy:decode(<<"1">>),
    ok.

rebar get-deps compile escriptize rebar get-deps编译escriptize
./test 。/测试

and the result is 结果是

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

Is there a way to overcome this ? 有办法克服这个问题吗?

The problem is that the erlang:load_nif/1 function does not implicitly use any search path nor do anything smart in trying to find the .so file. 问题是,在erlang:load_nif/1功能不会隐式使用任何搜索路径,也没有做任何事情,试图找到聪明.so文件。 It just tries to load the file literally as given by the file name argument. 它只是尝试按文件名参数的字面加载文件。 If it is not an absolute file name then it will try to load the file relative to the current working directory. 如果它不是绝对文件名,那么它将尝试相对于当前工作目录加载文件。 It loads exactly what you tell it to load. 正好加载你要它加载的内容。

So if you call erlang:load_nif("jiffy.so") then it will try to load "jiffy.so" from your current working directory. 因此,如果你调用erlang:load_nif("jiffy.so")那么它将尝试从你当前的工作目录加载"jiffy.so" A simple work around that I have used is to do something like this which uses the NIF_DIR environment variable: 我使用的一个简单的工作是使用NIF_DIR环境变量做这样的事情:

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

This can easily be extended to loop down a search path to find the file. 这可以很容易地扩展到循环搜索路径以查找文件。 Note that NIF_DIR is not a special name, just one I have "invented". 请注意, NIF_DIR不是一个特殊名称,只是我“发明”的名称。

It does not seem possible to load a nif from an escript because erlang:load_nif does not look into archives. 似乎无法从escript加载nif,因为erlang:load_nif不会查看存档。 This is because most operating systems require a physical copy of the *.so that can be mapped to memory. 这是因为大多数操作系统都需要可以映射到内存的*.so的物理副本。

The best way to overcome this is by copying the *.so files into the output directory of the escript. 解决此问题的最佳方法是将* .so文件复制到escript的输出目录中。

  {ok, _Bytes} = file:copy("deps/jiffy/priv/jiffy.so", "bin/jiffy.so"),

Take a look at the escript builder for edis . 看看在escript建设者edis You will see this is how they load the eleveldb's nif for execution from an escript. 您将看到这是他们如何从escript加载eleveldb的nif执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM