2

我正在尝试使用 Ruby 的 FFI 附加到 Google cityhash gem;它是一个 64 位和 128 位的非加密散列,类似于默认的 Ruby 散列函数 (murmur_hash 1),但更新了一点,更重要的是,它允许在散列上设置种子。

我在我的 Mac 上安装了 cityhash 以/usr/local/lib使用默认值。./configure这将一些库放置在/usr/local/lib

-rwxr-xr-x 1 root wheel 13720 Jul 11 15:16 /usr/local/lib/libcityhash.0.dylib
-rw-r--r-- 1 root wheel 43424 Jul 11 15:16 /usr/local/lib/libcityhash.a
lrwxr-xr-x 1 root wheel    19 Jul 11 15:16 /usr/local/lib/libcityhash.dylib -> libcityhash.0.dylib
-rwxr-xr-x 1 root wheel   977 Jul 11 15:16 /usr/local/lib/libcityhash.la

我正在使用 Mac OS X。gcc 版本是 4.6,这不是默认的 Mac gcc,但我也尝试过。

ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-darwin10.6.0]

ffi(在mac上安装了默认gcc,gcc 4.6不起作用?)

我做了我能做的最简单的模块:

require 'ffi'
module MyCityHash
  extend FFI::Library

  ffi_lib 'cityhash'
  attach_function  :CityHash64,  [:string, :size_t], :uint64    
end

但是当我尝试将此模块包含到任何 Ruby 类或脚本文件中时,我得到了错误:

/Users/charlesmartin/.rvm/gems/ruby-1.9.2-p180/gems/ffi-1.0.9/lib/ffi/library.rb:147:in `attach_function': Function 'CityHash64' not found in [libcityhash.dylib] (FFI::NotFoundError)

CityHash64 在 city.h 中有签名:

uint64 CityHash64(const char *buf, size_t len);

我将不胜感激有关如何调试此问题的任何见解。

4

1 回答 1

3

快速浏览一下 cityhash 项目,它看起来像是 C++,这意味着它们作为 C 符号不可见。名称将被破坏(如果您运行“nm libcityhash.dylib”,您可以看到这一点)。

你有几个选择:

  1. 计算出损坏的名称是什么(使用 nm 或 objdump),并将它们用作 attach_function 的本机函数名称。例如

    attach_function :CityHash64, :__Z10CityHash64PKcm, [ :string, :size_t ], :uint64
    

    其中“__Z10CityHash64PKcm”是 CityHash64 的符号名称,如 nm 所示(注意:不同平台的名称不同)。attach_function 的第一个参数是您希望它可以从 ruby​​ 调用的名称,因此您仍将其称为 MyCityHash.CityHash64()。

  2. 将 cityhash 函数公开为 C 符号(因此对 ruby​​-ffi 可见),方法是在要访问的每个函数前面加上“extern "C"”。例如

    extern "C" uint64 CityHash64(const char *buf, size_t len);
    

然后重建 libcityhash.dylib。

如果你正在创建一个 gem 分发给其他人,那么你必须使用选项 #1,除非你能说服 cityhash 维护者将这些函数公开给普通的旧 C。

于 2011-07-12T07:24:15.657 回答