sribe
How do you package a lib with a NIF?
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.exsto build shared library intopriv, and the wrapper module with@on_loadof:erlang.load_nif('priv/foo.so', nil) -
That worked: I could
iex -S mix run --no-haltthen 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.exandlib/foo_app/application.ex, and inmix.exsremoved themod:entry from the application.mix compileandmix testboth 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 inprivrelative 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 releasedoes not copy the NIF lib at all, not even if I addMix.Project.build_structureto the end of the compile mix task afterpriv/foo.sois 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/2with 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???
Most Liked
OvermindDL1
Not a supervisor, but a no-op Application is all you need, it doesn’t need to start anything at all. Priv directories are in relation to an Application root (as are config files and more too). ![]()
acalejos
Shameless plug, but you can check out a library i wrote that does this. It uses Application only to handle config options. Otherwise its just a wrapper for a C library. Everything in the mix.exs referring to “precompilation” might be useful too if you want to precompile your NIF shared libraries for a more seamless experience if publishing to Hex.
sribe
OK, I see now:
- Leave out
mod: ...in the application def inmix.exs - But do have a module which matches the
app: ...name - But leave the module totally empty, no
use Application, nostart/2








