I’m in the process of writing a NIF library application which in turn depends on a vendor’s shared lib (which has it’s own set of dependencies as well). My hope is to just keep all the various .so’s contained in /priv.
I’m using elixir_make to build my NIF’s code into it’s .so, which is also spit out into /priv by the makefile.
If I just run make, my /priv folder contains vendor.so, vendor_dep1.so, my_app_nif.so, which are all the files I would expect to be present.
I can successfully compile the elixir side of my application with: LD_LIBRARY_PATH=./priv mix compile, but I was wondering if there was a good way to set the LD_LIBRARY_PATH variable from within the project, so another user can just mix compile and it just works? Otherwise mix compile fails when compiling my nif module due to the @on_load bits normally set when writing nifs:
defmodule MyApp.Nif do
# code uglified to keep the post short
def load_nif do
nif_path = :my_app |> :code.priv_dir() |> List.to_string() |> Path.join("my_app_nif") |> String.to_charlist()
:erlang.load_nif(nif_path, 0) # Fails with 'vendor.so' cannot open shared object file: No such file or directory
Unfortunately :erlang.load_nif/2 doesn’t appear to have any options for specify additional library search paths. I’d be interested in hearing any suggestions on ways of getting around this? Short of just writing a run_me_not_mix_compile.sh script
Sorry, I probably didn’t explain quite right – the issue (as far as I can tell) isn’t in building the C code into its output artifact – it’s when I attempt to dynamically load that artifact at runtime (well, build time for the elixir code, but the C code has already been built at this point).
In the library that loads the vendor library it should just load the vendor library from the directory it already exists in, or in a hard coded relative location or so, why not just do it that way? You can get the path of the yourself (the library) and use that path to load the vendor library too.
Otherwise I ‘think’ LD_LIBRARY needs to be set ‘before’ the binary runs (the binary being the BEAM since it loads ‘your’ NIF).
Or just statically build the vendor library in to yours, that’s what I always prefer.
I’m definitely out of my depth here… I’d certainly prefer to statically link the vendor library, but all I have is the dynamic .so supplied by the vendor – no source code or static artifact to link against.
Your comment about the relative path put me in the right direction, I think. Linking with -Wl,-rpath="./path/to/priv" seems to work. Haven’t tested in a full release scenario with this library pulled into the main application, but I’m hopeful I can make it work. Thanks!