3

I looked through the questions here on StackOverflow and Googled around for an example of setting up a Basic NIF project in rebar for wrapping a C++ library.

I used to library project on GitHub as a guide:

https://github.com/tuncer/re2

My project is here:

https://github.com/project-z/emutton/

When I do a rebar compile && rebar eunit, I get a failure in the eunit test because it cannot find emtn.so:

$ rebar compile && rebar eunit 
==> emutton (compile)
==> emutton (eunit)
undefined
*** test module not found ***
**emtn

=ERROR REPORT==== 25-Jun-2013::12:21:55 ===
The on_load function for module emtn returned {error,
                                               {load_failed,
                                                "Failed to load NIF library: 'dlopen(/.../source/emutton/priv/emtn.so, 2): image not found'"}}
=======================================================
  Failed: 0.  Skipped: 0.  Passed: 0.
One or more tests were cancelled.
ERROR: One or more eunit tests failed.
ERROR: eunit failed while processing /.../source/emutton: rebar_abort

When I call rebar compile, it is only producing a single driver file, emtn_drv.so and no emtn.so:

$ tree priv 
priv
└── emtn_drv.so

0 directories, 1 file

I have an echo statement in c_src/build_deps.sh that I don't see output when I call rebar clean. It seems to behave as though my pre_hook and post_hook in rebar.config are completely ignored:

{pre_hooks, [{compile, "c_src/build_deps.sh"}]}.
{post_hooks, [{clean, "c_src/build_deps.sh clean"}]}.

Examples of no output shown from rebar:

$ rebar compile 
==> emutton (compile)
$ rebar clean 
==> emutton (clean)

Because I have cloned tuncer's RE2 bindings project and when I do a rebar compile see output from his build_deps.sh script. The permissions on mine match those on his:

-rwxr-xr-x  1 ajl  staff   891B Jun 25 12:30 c_src/build_deps.sh

Any idea what I'm missing here? I believe that rebar is configured correctly to call out to the script and do the compilation.

Hynek -Pichi- Vychodil
  • 26,174
  • 5
  • 52
  • 73
lenards
  • 141
  • 1
  • 8

1 Answers1

2

Your problem is that the line in your rebar.config

https://github.com/project-z/emutton/blob/master/rebar.config%20#L1

Doesn't match what you attempt to load

https://github.com/project-z/emutton/blob/master/src/emtn.erl#L25

You should either change the rebar.config to

{port_specs, [{"priv/emtn.so",["c_src/emtn_nif.c"]}]}.

and change emtn.erl to

erlang:load_nif(filename:join(PrivDir, "emtn"), 0).  % ?MODULE is an atom, I believe you need a string

Or change emtn.erl to

erlang:load_nif(filename:join(PrivDir, "emtn_drv"), 0).
Nym
  • 126
  • 1
  • 6
  • Thank Nym - I opted for the second approach. I didn't see how to control the name for the shared library, it was always "emtn_drv.so" (no matter how I named the files/etc). Here the committed changes: https://github.com/project-z/emutton/commit/2e7eed36ebbff39681a85860fc5fdcedda58fe1b – lenards Jun 25 '13 at 21:19
  • I actually figured out my problem, my rebar.config file was actually named `"rebar.config "`, with two spaces at the end. I hate to even admit I made this mistake, but I had to admit to the folks on rebar mailing list that were nice enough to try and answer my question. So, stupid mistake on my part. Now that I have `rebar.config` correctly named, the emtn.so & emtn_drv.so are properly built in `/priv/`. – lenards Jun 25 '13 at 22:02