I’m creating a NIF, and having some issues around packaging.
-
I started with an empty Elixir app, added the NIF source in its own directory, the appropriate task to
mix.exs
to build shared library intopriv
, and the wrapper module with@on_load
of:erlang.load_nif('priv/foo.so', nil)
-
That worked: I could
iex -S mix run --no-halt
then exercise the NIF usingFoo.func(...)
; also foo’s tests worked. -
I want to package this as a library that can just be pulled in as a normal dependency. It’s just simple functions, no need for its own application or any processes. So I deleted
lib/foo_app.ex
andlib/foo_app/application.ex
, and inmix.exs
removed themod:
entry from the application.mix compile
andmix test
both work. -
Now for the problems: using it. I create a new empty application, add the dependency
{:foo, path: "../foo", app: false}
. Compile works, but when I try to run (or test), the load of the NIF fails, because it’s not inpriv
relative to the executing project location, but rather in_build/dev/lib/local_dependency
-
It seems that maybe to load the NIF I should use
Application.app_dir(:foo, "priv")
but that gives an error about unknown application, while:code.priv_dir(:foo)
gives:bad_name
. Also, I note thatmix release
does not copy the NIF lib at all, not even if I addMix.Project.build_structure
to the end of the compile mix task afterpriv/foo.so
is created. -
So maybe I have to have an empty dummy application in the lib project, just to make all the build parts happy? And indeed, adding back a dummy app, setting the
mod:
to point to it, etc, makes things work. But of course the dummy app needs astart/2
with a return of the right form, so:
defmodule Foo.App do
use Application
def start(_, _) do
Supervisor.start_link([], [strategy: :one_for_one])
end
end
It seems silly to have to implement a do-nothing supervisor in order for the NIF lib to be copied and able to be located. Isn’t there a better way to structure and pull in this lib???