Erlang/OTP 19 [erts-8.1] [source] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Elixir 1.3.4
$ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description: Raspbian GNU/Linux 8.0 (jessie)
Release: 8.0
Codename: jessie
To provide some context, this is a Raspeberry PI 3 with an external WiFi card. The program I'm working on uses :wierl and :epcap to put that WiFi card in monitor mode and read packets. The :epcap module includes a shared library which is built as deps/procket/priv/procket.so (btw, the built in WiFi card doesn't support monitor mode, that's why I'm using an external one.)
The project directory is sensor and mix escript.build builds the app as sensor.
It worked until I added the dependency from :epcap.
Then
$ ./sensor wlan1
11:22:03.317 [warn] The on_load function for module procket returned {:error,
{:load_failed,
'Failed to load NIF library: \'/home/me/sensor/sensor/../priv/procket.so: cannot open
shared object file: Not a directory\''}}
** (UndefinedFunctionError) function :procket.socket/3 is undefined (module :procket
is not available)
:procket.socket(:inet, :dgram, 0)
src/wierl_config.erl:175: :wierl_config.down/1
(sensor) lib/antenna.ex:4: Antenna.enter_monitor_mode/1
(sensor) lib/sensor.ex:13: Sensor.start/1
(elixir) lib/kernel/cli.ex:76: anonymous fn/3 in Kernel.CLI.exec_fun/2
Note that the path /home/me/sensor/sensor/../priv/procket.so is obviously wrong because of two reasons:
1) The second occurrence of sensor is actually a file (the app) and not a directory, and the path is wrong even if I manually create a priv dir under /home/me/sensor
2) The shared library is in deps/procket/priv/procket.so
There is another shared library in deps/epcap/priv/epcap_drv.so but it probably failed first on loading procket.so.
Running the application as a mix task or from iex -S mix works.
Escript should load the shared library from its path /home/me/sensor/deps/procket/priv/procket.so
Unfortunately that's a limitation of escripts. They cannot access anything in priv and therefore they cannot access embedded .so files. In other words, it is not currently possible to build escripts with NIFs in them.
For me, it works if I copy the NIFs into the path that my command line app built with mix escript.build states in its error message. In my case, I'm using fast_xml which comes with two NIFs, fxml.so and fxml_stream.so.
Without any further action by me, using my app results in
[error] failed to load NIF /Users/...../priv/lib/fxml_stream: Failed to load NIF library: 'dlopen(/Users/......./priv/lib/fxml_stream.so, 2): image not found'
Copying the libs into /priv/lib, the app works as expected. It's a little crude for a production environment, but can probably be automatized with a shell script.