Elixir NIF- Hello World example on x64 Mac OSX
Asked Answered
O

1

9

Hi I'm trying to get the Hello World example for Erlang NIF (Native Implemented Function) shown here http://www.erlang.org/doc/man/erl_nif.html to work from Elixir on OSX 64bit.

First I create the C-code:

/* niftest.c */
#include "erl_nif.h"

static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
    return enif_make_string(env, "Hello world!", ERL_NIF_LATIN1);
}

static ErlNifFunc nif_funcs[] =
{
    {"hello", 0, hello}
};

ERL_NIF_INIT(niftest,nif_funcs,NULL,NULL,NULL,NULL)

Then I successfully compile it using gcc for 64 bit architecture as suggested here Erlang NIF Test -- OS X Lion

gcc -undefined dynamic_lookup -dynamiclib niftest.c -o niftest.so -I /usr/local/Cellar/erlang/R14B02/lib/erlang/usr/include

which produces the necessary file niftest.so that I should be able to interface-into from Erlang/Elixir. My Elixir (niftest.ex) looks like this (inspired by a more complex example reported here):

defmodule Niftest do
 @onload :init
  def init() do
    :erlang.load_nif("./niftest", 0)
    :ok
  end

  def hello() do
    "NIF library not loaded"
  end

end

Now with niftest.so and niftest.ex in the same directory I fire up elixir using iex and type in Niftest.hello and all I get back is: "NIF library not loaded"

Am I missing a vital step? - please help!

Odine answered 27/4, 2015 at 9:29 Comment(0)
D
11

The load of the library is failing silently. You can assert that it succeeds using:

:ok = :erlang.load_nif("./niftest", 0)

This results in an error:

** (MatchError) no match of right hand side value:
{:error, {:bad_lib, 'Library module name \'niftest\' does not match calling module \'\'Elixir.Niftest\'\''}}
niftest.ex:4: Niftest.init/0

That happens because a NIF lib can only be called from its "owning" module. The name of that module is the first argument to the ERL_NIF_INIT macro, so you can fix this by changing that call and recompiling:

ERL_NIF_INIT(Elixir.Niftest,nif_funcs,NULL,NULL,NULL,NULL)

There is also a typo in the load hook. It should be:

@on_load :init
Dogwatch answered 27/4, 2015 at 10:16 Comment(4)
You are right - yours will be the accepted answer - many thanks!Odine
It turns out that the @onload :init directive doesn't works as expected either - so I have to manually call Niftest.init before I call Nifteast.hello. Not sure why.Odine
@onload doesn't work because it should be @on_load. Updated the answerProceleusmatic
doh! too much javascript on the brain - thanks for spotting that!Odine

© 2022 - 2024 — McMap. All rights reserved.