JesseBuesking JesseBuesking -4 years ago 210
Ruby Question

ruby native extension: undefined symbol

I'm attempting to create a ruby native extension, but when I run

which uses
to build my project and run my tests under
, I get the following error when the tests are run:

./home/jbuesking/.rbenv/versions/2.3.0/bin/ruby: symbol lookup error:
/home/jbuesking/repositories/example_project/lib/example_project/ undefined symbol: some_function

I'm pretty sure my files are not being linked correctly and that I need to alter my
in some way, but I'm not sure how.

I've created a simple repository that demonstrates the issue over on GitHub. It'll fail with the same error if you clone it and run
from the projects root.

Some additional information:

  • I used the ruby gem
    to create the project via
    sow example_project

  • The failing function is attempting to call a function defined in the subdirectory
    . My actual project uses a git submodule from the
    directory, which in turn sets up the submodule as a subdirectory. The submodule is a c project with a flattened structure (all files in the root directory). Note: That wording may be confusing, but the key point is that there's a nested c project defined at
    which has methods I'm trying to call.

Let me know if any clarification is needed, and I'll do my best to provide it.

Answer Source

So, there are some interesting issues you have here. By default, mkmf doesn't actually support specifying multiple directories for building sources.

There is a workaround, as seen here (Takehiro Kubo's comment about setting objs):

Basically, you construct the $objs global in your extconf.rb file yourself.

Using your github code, here's what I added to the extconf.rb and got to work


globs = [".", "c_example_project"].map do |directory|
  File.join(File.dirname(__FILE__), directory)

$objs = Dir.glob("{#{globs}}/*.c").map do |file|
  File.join(File.dirname(file), "#{File.basename(file, ".c")}.o")

Notice I'm actually constructing an absolute path to each of the c sources, for some reason rake-compiler was freaking out if we were just globbing with {.,c_example_project}/*.c, presumably since it's running the extconf.rb file from another directory.

In addition, your tests/c extensions have a few errors in them. Making the following change in example_project.c fixes the test failure:

 static VALUE example_project_c_code_function()
-    return some_function();
+    VALUE _string = rb_str_new2(some_function());
+    int _enc = rb_enc_find_index("UTF-8");
+    rb_enc_associate_index(_string, _enc);
+    return _string;


Basically even though you're checking the c_example_project.h header in your extconf.rb, you're not actually generating the object file where some_function is defined. So, when linking the final dynamic library that ruby loads up, there's no definition for some_function and you get your error.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download