2013-03-25 16 views
9

Mogę użyć nif, jeśli sam napiszę ten skrypt, ale kiedy używam zbrojenia, nie można znaleźć funkcji nif. Myślę, że to dlatego, że obiekty * .so nie są upakowane jak pliki belek. Oto prosty przykład;erlang rebar escriptize & nifs

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. 

zbrojenie get-deps skompilować escriptize
./test

a wynik jest

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 

Czy istnieje sposób na pokonanie tego?

+0

Z błędu wygląda na to, że 'jiffy.beam' nie może zostać znaleziony, a nie' * .so'. Może 'escriptize' bierze pod uwagę tylko wiązki z' ebin' ignorujących zależności '' ebin's? –

+0

@ Ed'ka, nie, jeśli dodasz zależność, która nie jest nif, działa dobrze. – cashmere

+0

Ale jeśli spróbujesz wywołać 'jiffy: decode/1' z' jiffy.so' usuniętym z 'priv' powinieneś otrzymać błąd' Failed to load NIF library', a nie 'undefined function' –

Odpowiedz

3

Problemem jest to, że funkcja erlang:load_nif/1 robi nie niejawnie wykorzystywać każdą ścieżkę przeszukiwania ani zrobić coś inteligentnego, próbując znaleźć plik .so. Po prostu próbuje załadować plik dosłownie tak, jak podaje argument nazwy pliku. Jeśli nie jest to bezwzględna nazwa pliku, spróbuje załadować plik w stosunku do bieżącego katalogu roboczego. Ładuje dokładnie, co powiesz mu załadować.

Jeśli więc zadzwonisz pod numer erlang:load_nif("jiffy.so"), spróbujesz załadować "jiffy.so" z bieżącego katalogu roboczego. Prosta praca dokoła że użyłem jest zrobić coś takiego, który wykorzystuje zmienną NIF_DIR środowiska:

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

ten można łatwo rozszerzyć do pętli w dół ścieżki wyszukiwania, aby znaleźć plik. Zauważ, że NIF_DIR nie jest specjalną nazwą, tylko jedną "wymyśloną".

+0

Edytowałem jiffy kod, aby to zrobić, ale nie pomogło. Jest to podobne do tego, co zasugerował @lastcanal. Zamiast kopiować do .so do poprawnego miejsca, szukasz go rekurencyjnie. Myślę, że ten problem nie jest relavent do ładowania .so.Jak zauważył Ed'ka, oznacza to niezdefiniowaną funkcję: dekodowanie/1. – cashmere

+0

Tak, ale nigdy nie podano, gdzie powinno się zdefiniować 'jiffy: decode/1'. Jeśli znajdował się w pliku .so, powodem mógł być plik, który nigdy nie został załadowany. Lub w ogóle nie zdefiniowane. – rvirding

+0

jest zdefiniowany [tutaj] (https://github.com/davisp/jiffy/blob/master/src/jiffy.erl#L10). I powoduje wywołanie rzeczywistej funkcji nif, jeśli została zdefiniowana poprawnie zdefiniowana iw ścieżce kodu powinna dać erlang: nif_error prawda? – cashmere

1

Nie można załadować nif z eskrytu, ponieważ erlang:load_nif nie zagląda do archiwów. Wynika to z faktu, że większość systemów operacyjnych wymaga fizycznej kopii modelu *.so, która może zostać zmapowana do pamięci.

Najlepszym sposobem na pokonanie tego problemu jest skopiowanie plików * .so do katalogu wyjściowego eskrytu.

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

Spójrz na escript builder dla edis. Zobaczysz, w jaki sposób ładują nif eleveldb do wykonania z eskrytu.

+0

Kod edis jest bardzo podobny do [kodu pręta zbrojeniowego] (https://github.com/rebar/rebar/blob/master/src/rebar_escripter.erl#L69). Próbowałem skopiować 'jiffy.so' do tego samego katalogu z odnośnikiem, ale nie pomogło. – cashmere