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
而不是 long
(PRIuSIZE
是非标准的,在 "ruby/ruby.h"
中定义)。并且
cMyMalloc = rb_const_get(rb_cObject, rb_intern("MyMalloc"));
到
cMyMalloc = rb_define_class("MyMalloc", rb_cObject);
实际定义 MyMalloc
class.
我正在尝试按照本教程在 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
而不是 long
(PRIuSIZE
是非标准的,在 "ruby/ruby.h"
中定义)。并且
cMyMalloc = rb_const_get(rb_cObject, rb_intern("MyMalloc"));
到
cMyMalloc = rb_define_class("MyMalloc", rb_cObject);
实际定义 MyMalloc
class.