sribe

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.exs to build shared library into priv, 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 using Foo.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 and lib/foo_app/application.ex, and in mix.exs removed the mod: entry from the application. mix compile and mix 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 in priv 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 that mix release does not copy the NIF lib at all, not even if I add Mix.Project.build_structure to the end of the compile mix task after priv/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 a start/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???

Most Liked

OvermindDL1

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). :slight_smile:

acalejos

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

sribe

OK, I see now:

  • Leave out mod: ... in the application def in mix.exs
  • But do have a module which matches the app: ... name
  • But leave the module totally empty, no use Application, no start/2
sribe

sribe

When I tried start as a noop, it complained about the return value. (I did not try just returning {:ok, nil})

When I remove both the start function and use Application, it still works. Apparently the use is not needed, just a module whose name matches the app: key in the project def is enough for it to base paths on that module.

Also, instead of function application returning [], I just removed that function altogether from mix.exs, and it still works.

sribe

sribe

I didn’t realize that, and didn’t try it–just assumed something would complain about the bogus pid.

The key to leaving out start in the module is leaving out mod: ... in mix.exs–that results in it not trying to call start, and also seems to allow for dropping use Application

Where Next?

Popular in Questions Top

vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
gonzofish
I’m currently trying to understand how to join three tables using Ecto. All the examples I’ve seen use 2, so maybe I’m just missing somet...
New
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New
chewm
Hi guys, nice to meet you to the whole forum, I’m new here, I’m trying to configure visual studio code for elixir, right now the intellis...
New
jc00ke
Expanding on this topic: https://forum.elixirforum.net/t/map-typespec-question/19217 Let’s say I have a map with required and optional k...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

Other popular topics Top

JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New

We're in Beta

About us Mission Statement