【问题标题】:Why does Ruby FFI not attach functions from custom shared object library为什么 Ruby FFI 不附加自定义共享对象库中的函数
【发布时间】:2013-07-23 11:48:39
【问题描述】:

我想使用 ffi gem 在 Ruby 2.0 中加载自定义 C++ 函数。在 irb 会话中加载我的自定义库时,我在 attach_function 调用期间收到错误:

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

这是我创建和检查 libbridge 共享对象的方式:

我的库有一个头文件:

文件:bridge.h

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

库实现:

文件:bridge.cpp

#include <iostream>

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

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

以及我链接到我的新库的二进制代码:

文件: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";
}

首先我将我的库编译为目标代码:

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

然后我把它变成一个共享对象:

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

我去掉调试符号:

$ strip -o libbridge.so libbridge.so 

并将其移入我的系统:

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

然后我让它可执行并运行 ldconfig:

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

空头检查:

$ 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)

我从我的工作目录中删除了语言环境版本:

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

然后我编译我的二进制文件:

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

我成功执行并得到了我期望的输出:

$ ./bridger
foobarrrr
Adding 4 and 2: 6

现在我创建一个 ruby​​ 模块 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

当我现在在 irb 会话中加载该代码时,我总是收到此错误:

$ 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>'

我不明白,这里的问题是什么。我的库显然导出了 :add 和 :fooBar 函数,否则我的桥接器二进制文件将无法成功链接到该库。相反,Ruby ffi 无法查看和挂载这些函数。

谁能在这里指出我正确的方向?

问候 费利克斯

【问题讨论】:

    标签: c++ ruby shared-libraries ffi


    【解决方案1】:

    ffi 需要一个 c 函数,所以它找不到你的 c++ 函数,因为名称 mangling c++ 确实如此。

    您需要告诉链接器使函数可以从 c 访问,例如通过(在您的 .h 文件中)执行

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

    我怀疑 FFI 也不知道如何处理期望 std::string 作为参数的函数

    【讨论】:

    • 嘿弗雷德里克,感谢您的提示。我从标题和源代码中完全删除了函数 fooBar。将您的行添加到我的标题中,重新编译并重新安装了 lib。但是错误还是一样。
    • 当我将 bridge.cpp 重命名为 bridge.c 并使用 gcc 而不是 g++ 时,我得到了这个工作。但我真正想要使用的目标库是 c++。那我该如何利用它呢? FFI 不支持 C++ 吗?
    • 你的 bridge.cpp 是否包含 bridge.h ?
    • 我的错!就是这样。感谢您的帮助。
    【解决方案2】:

    在 OSX 上,对我有用的是使用 -dynamiclib 进行编译:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-27
      • 2020-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-01
      相关资源
      最近更新 更多