Ruby Gems C 扩展示例不工作

Ruby Gems C extension example not working

我正在尝试按照本教程在 ruby gems http://guides.rubygems.org/gems-with-extensions/ 中构建 C 扩展。

我有以下文件:

ext/my_malloc/extconf.rb

require "mkmf"

abort "missing malloc()" unless have_func "malloc"
abort "missing free()"   unless have_func "free"

create_makefile "my_malloc/my_malloc"

ext/my_malloc/my_malloc.c

#include <ruby.h>

struct my_malloc {
  size_t size;
  void *ptr;
};

static void
my_malloc_free(void *p) {
  struct my_malloc *ptr = p;

  if (ptr->size > 0)
    free(ptr->ptr);
}

static VALUE
my_malloc_alloc(VALUE klass) {
  VALUE obj;
  struct my_malloc *ptr;

  obj = Data_Make_Struct(klass, struct my_malloc, NULL, my_malloc_free, ptr);

  ptr->size = 0;
  ptr->ptr  = NULL;

  return obj;
}

static VALUE
my_malloc_init(VALUE self, VALUE size) {
  struct my_malloc *ptr;
  size_t requested = NUM2SIZET(size);

  if (0 == requested)
    rb_raise(rb_eArgError, "unable to allocate 0 bytes");

  Data_Get_Struct(self, struct my_malloc, ptr);

  ptr->ptr = malloc(requested);

  if (NULL == ptr->ptr)
    rb_raise(rb_eNoMemError, "unable to allocate %ld bytes", requested);

  ptr->size = requested;

  return self;
}

static VALUE
my_malloc_release(VALUE self) {
  struct my_malloc *ptr;

  Data_Get_Struct(self, struct my_malloc, ptr);

  if (0 == ptr->size)
    return self;

  ptr->size = 0;
  free(ptr->ptr);

  return self;
}

void
Init_my_malloc(void) {
  VALUE cMyMalloc;

  cMyMalloc = rb_const_get(rb_cObject, rb_intern("MyMalloc"));

  rb_define_alloc_func(cMyMalloc, my_malloc_alloc);
  rb_define_method(cMyMalloc, "initialize", my_malloc_init, 1);
  rb_define_method(cMyMalloc, "free", my_malloc_release, 0);
}

我执行以下操作来构建扩展:

$ cd ext/my_malloc
$ ruby extconf.rb
checking for malloc()... yes
checking for free()... yes
creating Makefile
$ make
compiling my_malloc.c
linking shared-object my_malloc.bundle
$ cd ../..
$ ruby -Ilib:ext -r my_malloc -e "p MyMalloc.new(5).free"

但是,我在最后一条命令中收到以下错误:

/Users/Daniel/.rbenv/versions/2.1.6/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- my_malloc (LoadError)
from     
/Users/Daniel/.rbenv/versions/2.1.6/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'

请注意,我正在使用 rbenv,我已经尝试 运行 rbenv rehash 并且我是 运行 版本 2.1.6。

正确的shell命令是:

ruby -Iext/my_malloc -r my_malloc -e "p MyMalloc.new(5).free"

代码还有其他一些错误。正确

rb_raise(rb_eNoMemError, "unable to allocate %ld bytes", requested);

rb_raise(rb_eNoMemError, "unable to allocate %" PRIuSIZE " bytes", requested);

因为 requested 的类型是 size_t 而不是 longPRIuSIZE 是非标准的,在 "ruby/ruby.h" 中定义)。并且

cMyMalloc = rb_const_get(rb_cObject, rb_intern("MyMalloc"));

cMyMalloc = rb_define_class("MyMalloc", rb_cObject);

实际定义 MyMalloc class.