NIF causing weird behaviour when used in an external dependency

I’m using erlpuzzle as a NIF so I can use it in Elixir. It has been working well, but a couple of days ago I refactored my code to extract some methods to another module, and although running on my local machine works, when I deploy it, it gives a weird error.

Slogan: init terminating in do_boot ({load_failed,[Elixir.MyAppCommon.Utils,Elixir.MyAppCommon]})

To give some context, before move erlpuzzle to this new module (in a git repository), it worked well, and not sure why it complains about MyAppCommon.Utils, since it wasn’t changed and worked well before.

This is my code to use the NIF.

defmodule :puzzle do
  @on_load :load_nifs

  def load_nifs do
    file_name =
      case :os.type() do
        {:unix, :darwin} -> "puzzle_osx"
        {:unix, :linux} -> "puzzle_deb"
        _ -> raise "Unsupported operative system!"
      end

    path = "#{:code.priv_dir(:myapp)}/#{file_name}"
    :erlang.load_nif(String.to_charlist(path), 0)
  end

  def cvec_from_file(_) do
    raise "NIF cvec_from_file/1 not implemented"
  end
  
...
end

I’m under the impression it is because I’m using defmodule :puzzle do instead of something like defmodule MyApp.Puzzle do, but if I try to use that, it gives a warning.

{:error, {:bad_lib, 'Library module name \'puzzle\' does not match calling module \'\'Elixir.MyApp.Puzzle\'\''}}

I’ve found this issue on StackOverflow, but I’m not sure where I need to rename the erlpuzzle to match my module name, or if there is a simpler solution.

How do you set up the NIF module in the native sources? The ERL_NIF_INIT macro (or its equivalent) specifies the module name.

Since it is working locally and does fail on the server, my assumption is, that you develop on a mac and have the setting correct there, while you deploy to linux and missed to change the module name there.

Also you should use :erlang.nif_error/1,2 isntead of raiseing to make dialyzer happy.

1 Like

I will have a look into ERL_NIF_INIT, and how to add it to the erlpuzzle.

Since it is working locally and does fail on the server, my assumption is, that you develop on a mac and have the setting correct there, while you deploy to linux and missed to change the module name there.

That gives a specific error, like cannot load puzzle module. That happened yesterday because of a bug in the code, but I’m isn’t related to the same issue.

I’m trying to understand which line of code is causing this. I’ve moved back only puzzle.ex and it is still happening.

The problem is, that the specified modulename in your NIF-library seems to be incorrect, The module from which it is loaded and in the source, they need to match.

If your project is available publicly and you share the link to the repo, we might take a look at it and help you fixing it.

Yes, I know. I will look again later in the day to this issue, the only file left it is a utils module that use :puzzle. May, even the puzzle is defined in another module, I can’t use in this one.

Ok, so I had a couple of hours to look at this again and I kinda “found” the issue, not sure why but it related to some files or folders that are kept from the previous release by edeliver/distillery. I didn’t test a folder specific, but I think I needed to remove the folder <myapp>/releases/ or <myapp>/lib/ (or both).

There was a point that was giving not just my module errors, but about every other module loaded in the main application.

=====
===== LOGGING STARTED Fri Nov 15 21:32:54 WET 2019
=====
{"init terminating in do_boot",{load_failed,['Elixir.MyAppCommon.Utils','Elixir.MyAppCommon.Title','Elixir.MyAppCommon']}}
init terminating in do_boot ({load_failed,[Elixir.MyAppCommon.Utils,Elixir.MyAppCommon.Title,Elixir.MyAppCommon]})

Crash dump is being written to: erl_crash.dump...done

=====
===== LOGGING STARTED Fri Nov 15 21:39:57 WET 2019
=====
{"init terminating in do_boot",{load_failed,['Elixir.MyAppWeb.ModelVersionView','Elixir.MyApp.Sapo','Elixir.MyApp.Book.Color','Elixir.MyApp.Book','Elixir.MyApp.Utils.Image','Elixir.MyAppWeb.Live.SidebarComponent',puzzle,'Elixir.MyAppWeb.LayoutLive','Elixir.MyAppWeb.View.Helper.Book','Elixir.MyAppWeb.View.Helper','Elixir.MyAppWeb.BookView','Elixir.MyApp.Repo','Elixir.MyApp.PlateDate','Elixir.MyApp.ModelVersionLive.Show','Elixir.MyApp.Manager.Color','Elixir.MyApp.Manager.Sapo','Elixir.MyApp']}}
init terminating in do_boot ({load_failed,[Elixir.MyAppWeb.ModelVersionView,Elixir.MyApp.Sapo,Elixir.MyApp.Book.Color,Elixir.MyApp.Book,Elixir.MyApp.Utils.Image,Elixir.MyAppWeb.Live.Sid

Crash dump is being written to: erl_crash.dump...done

I will move on from the time being, but need to check if is some kind of bug with edeliver or distillery.