1

I am trying to follow this tutorial on building c extension in ruby gems http://guides.rubygems.org/gems-with-extensions/.

I have the following files:

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);
}

I do the following to build the extension:

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

However, I get the following error on the last command:

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

Note, I'm using rbenv, I've tried running rbenv rehash and I'm running version 2.1.6.

Daniel Nill
  • 5,539
  • 10
  • 45
  • 63

1 Answers1

3

The correct shell command is:

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

The code also has some other mistakes. Correct

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

to

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

since requested has type size_t and not long (PRIuSIZE is non-standard and defined in "ruby/ruby.h"). And

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

to

cMyMalloc = rb_define_class("MyMalloc", rb_cObject);

to actually define the MyMalloc class.

cremno
  • 4,672
  • 1
  • 16
  • 27