Вопрос

I'd like to load a custom C++ function inside Ruby 2.0 using the ffi gem. When loading my custom library in an irb session I get an error during the attach_function call:

FFI::NotFoundError: Function 'add' not found in [/usr/local/lib/libbridge.so]

Here's the way I created and checked my libbridge shared object:

I got a header file for my library:

file: bridge.h

std::string fooBar(std::string bar);
int add(int a, int b);

The libraries implementation:

file: bridge.cpp

#include <iostream>

std::string fooBar(std::string bar)
{
  return "foo" + bar;
}

int add(int a, int b)
{
  return a + b;
}

And the code for the binary that I link against my new library:

file: bridger.cpp

#include <iostream>
#include "bridge.h"

int main(int argc, char* argv[])
{
  std::string foobar = fooBar("barrrr");
  std::cout << foobar << "\n";

  std::cout << "Adding 4 and 2: " << add(4,2) << "\n";
}

First I compile my lib to object code:

$ g++ -c -Wall -Werror -fpic bridge.cpp

Then I make it a shared object:

$ g++ -shared -o libbridge.so bridge.o

I strip the debug symbols:

$ strip -o libbridge.so libbridge.so 

And move it into my system:

$ sudo mv libbridge.so /usr/local/lib/

Then I make it executable and run ldconfig:

$ sudo chmod 0755 /usr/local/lib/libbridge.so 
$ sudo ldconfig

Short check:

$ ldd /usr/local/lib/libbridge.so 
    linux-gate.so.1 =>  (0xb7781000)
    libstdc++.so.6 => /usr/lib/i386-linux-gnu/libstdc++.so.6 (0xb7689000)
    libm.so.6 => /lib/i386-linux-gnu/i686/cmov/libm.so.6 (0xb7663000)
    libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xb7645000)
    libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xb74e2000)
    /lib/ld-linux.so.2 (0xb7782000)

I remove the locale versions from my working dir:

$ rm -f bridge.so
$ rm -f bridge.o

And I compile my binary:

$ g++ -Wall -o bridger bridger.cpp -lbridge

I successfully execute it and get the output I expected:

$ ./bridger
foobarrrr
Adding 4 and 2: 6

Now I create a ruby module ffi_test.rb:

require "ffi"
module FfiTest

  extend FFI::Library
  ffi_lib_flags :now, :global
  ffi_lib "/usr/local/lib/libbridge.so"
  attach_function :add, [:int, :int], :int
  attach_function :fooBar, [:string], :string

end

When I load that code in an irb session now I always get this error:

$ irb
2.0.0p247 :001 > load "ffi_test.rb"
FFI::NotFoundError: Function 'add' not found in [/usr/local/lib/libbridge.so]
    from /home/me/.rvm/gems/ruby-2.0.0-p247@global/gems/ffi-1.9.0/lib/ffi/library.rb:251:in `attach_function'
    from ffi_test.rb:8:in `<module:EricInterface>'
    from ffi_test.rb:3:in `<top (required)>'
    from (irb):1:in `load'
    from (irb):1
    from /home/me/.rvm/rubies/ruby-2.0.0-p247/bin/irb:16:in `<main>'

I do not understand, what the problem here is. My library obviously exports the :add and :fooBar functions, otherwise my bridger binary would not successfully link against this library. Ruby ffi instead is not able to see and mount these functions.

Can anyone point me into the right direction here?

Regards Felix

Это было полезно?

Решение

ffi is expecting a c function, so it's not finding your c++ functions because of the name mangling c++ does.

You need to tell the linker to make the functions accessible from c, eg by doing (in your .h) file

extern "C" {
    int add(int a, int b);
}

I suspect FFI also won't know what to do with a function that is expecting a std::string as a argument

Другие советы

On OSX, what worked for me is to compile with -dynamiclib:

g++ -dynamiclib -o mylib.dylib mylib.cpp

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top