Two problems creating a C++ extension to Ruby

Ask a Question related to Ruby, Design and Development.

  1. #1

    Default Two problems creating a C++ extension to Ruby

    Hello,

    I'm having some trouble with my first C++ extension for Ruby. The extension
    is a wrapper for the id3lib library providing my own interface over top that
    of the library. I've encountered two problems, one on the build side of
    things and anther from within Ruby when I tried to test the extension.

    To create the makefile for the extension I'm using the 'mkmf'
    module. Because the extension relies on libid3.so I tried to test for that
    library using :have_library, but I've not been able to supply a second
    argument that will cause the method to return true. Here is what I tried:

    require 'mkmf'
    if have_library( "id3", "ID3_Tag::ID3_Tag" ) then
    create_makefile("id3lib")
    else
    puts "libid3 not found."
    end

    I think the trouble is that all of the symbol names in the library are
    mangled by the C++ compiler. Though, even when I substitute a mangled name
    for the second argument the test fails. I've gotten around this by not doing
    a library test and just calling create_makefile and then editing the
    resulting makefile by hand to have the extension .so linked against
    libid3.so.

    I looked at the FXRuby source, but it uses a different build method than
    mkmf and I don't know of any other extensions that use C++ libraries. Should
    I try a different build method? (Can someone recommend one?)

    The second problem came up when I tried to test the extension. After
    creating a new ID3Lib object, which opens an mp3 file, the script calls the
    :artist method to return a string containing the value of that tag. That
    method call generates an ArgumentError exception with the error message
    "NULL pointer given".

    I've tried to isolate where that error is generated and I can only say that
    it seems to come from within Ruby. Replacing the body of the C++ function,
    that is called for the no argument version of :artist, with a statement to
    return a Fixnum still results in the "NULL pointer given" exception. So it
    seems that the statements within id3_get_album() don't cause the exception,
    but maybe someother part of my C++ code is the problem?

    For people who may know more about this and need to look at the code it can
    be gotten here: [url]http://roland.sw.edu/matthew/id3lib_ext.tar.gz[/url] If for some
    reason that hostname doesn't resolve (as seems to happen outside our
    college) then substitute the IP address 164.106.190.246 for the hostname.

    If anyone can help, I would be very appreciative. If you look at the code, I
    am also open to comments and suggestions not related to the above problems.

    Thanks for your help, Matthew.
    Matthew Miller Guest

  2. Similar Questions and Discussions

    1. Any Extension for Ruby On Rails on DW
      Hello, I am planning to quit PHP and start developing in Ruby on Rails. Their MVC model is really great and plus MS has also appreciated this...
    2. Ruby - C++ extension
      Hello! I am trying to create a new Ruby extension, which eventually will give to Ruby the functionality of a C++ project. So far, the...
    3. Ruby Extension/DLL Help
      Hi, Recently i started writing a Ruby extension. This Extension is providing access to a dll-library. It has been written in c. Compiling works...
    4. Exception handling in ruby extension
      Quick question, How do you handle exceptions in a ruby extension? I see rb_rescue, but it don't see how I get at the exception object in func2. ...
    5. Problems with the Ruby MySQL Interface 2.4.4a and Ruby 1.8.0 on OS X
      Hola. The Ruby MySQL Interface 2.4.4a package compiles fine with Ruby 1.8.0 on the OS X 10.2.6 I'm running, but as soon as I try to run the test...
  3. #2

    Default Re: Two problems creating a C++ extension to Ruby

    Matthew Miller wrote:
    > for the second argument the test fails. I've gotten around this by not doing
    > a library test and just calling create_makefile and then editing the
    > resulting makefile by hand to have the extension .so linked against
    > libid3.so.
    Since libid3.so is not optional in this case, I think it is OK to just
    assume that it's there. To avoid having to edit the Makefile, though,
    try adding this line to your extconf.rb script before the final call to
    create_makefile():

    $libs = append_library($libs, "id3")

    Note that you don't include the "lib" prefix or the ".so" extension for
    the library file name.
    > I looked at the FXRuby source, but it uses a different build method than
    > mkmf and I don't know of any other extensions that use C++ libraries. Should
    > I try a different build method? (Can someone recommend one?)
    FXRuby does use the mkmf library for the part that truly is a C++
    extension; see the ext/fox subdirectory of the FXRuby source
    distribution. As it turns out, FXRuby is sort-of a hybrid of C++
    extension code and pure Ruby code, and so I'm using Minero Aoki's
    setup.rb library to package-up the whole thing.
    > The second problem came up when I tried to test the extension. After
    > creating a new ID3Lib object, which opens an mp3 file, the script calls the
    > :artist method to return a string containing the value of that tag. That
    > method call generates an ArgumentError exception with the error message
    > "NULL pointer given".
    OK. So if we look at the extension code for the ID3Lib#artist method:

    static VALUE id3_get_artist( VALUE obj ) {
    ID3Lib* id3 = static_cast<ID3Lib*>(DATA_PTR( obj ));
    return rb_str_new2( id3->artist );
    }

    This almost certainly indicates that the id3->artist field is a NULL
    pointer. So it is the call to rb_str_new2() that is generating the "NULL
    pointer given" error message.
    > I've tried to isolate where that error is generated and I can only say that
    > it seems to come from within Ruby. Replacing the body of the C++ function,
    > that is called for the no argument version of :artist, with a statement to
    > return a Fixnum still results in the "NULL pointer given" exception. So it
    > seems that the statements within id3_get_album() don't cause the exception,
    > but maybe someother part of my C++ code is the problem?
    The C++ function that implements the ID3Lib#artist method is
    id3_get_artist(), not id3_get_album(). You did indeed put some debugging
    code in id3_get_album(), but that's not the one that's getting invoked
    when you call ID3Lib#artist.

    I think the problem may be that when you construct the C++ ID3Lib object
    you're not calling its constructor properly. If I look at your id3_new()
    function:

    static VALUE id3_new( int argc, VALUE* argv, VALUE self ) {
    ID3Lib* id3 = ALLOC( ID3Lib );
    VALUE mp3_info = Data_Wrap_Struct(self, 0, id3_free,
    (void*) id3 );
    rb_obj_call_init( mp3_info, argc, argv );
    return mp3_info;
    }

    I'm wondering if that if that first line shouldn't perhaps be:

    ID3Lib* id3 = new ID3Lib;

    If that's not the problem, you might also want to add some print
    statements to the id3_initialize() function, after the call to
    read_tags(), to convince yourself that at that point the
    id3_struct->artist field really is a non-NULL string.
    > If anyone can help, I would be very appreciative. If you look at the code, I
    > am also open to comments and suggestions not related to the above problems.
    The code looks really good to me. I suspect that this is just a little
    bug somewhere that you'll be able to fix without much trouble.

    Good luck,

    Lyle

    Lyle Johnson Guest

  4. #3

    Default Re: Two problems creating a C++ extension to Ruby

    On Sun, 28 Sep 2003, Lyle Johnson wrote:
    > Matthew Miller wrote:
    >
    > > for the second argument the test fails. I've gotten around this by not doing
    > > a library test and just calling create_makefile and then editing the
    > > resulting makefile by hand to have the extension .so linked against
    > > libid3.so.
    >
    > Since libid3.so is not optional in this case, I think it is OK to just
    > assume that it's there. To avoid having to edit the Makefile, though,
    > try adding this line to your extconf.rb script before the final call to
    > create_makefile():
    >
    > $libs = append_library($libs, "id3")
    Matthew can also use the have_library function without a second argument.
    In this case, ruby will use "main" as the default. "main" is of course
    defined by the test program itself, so it will not be the cause of any
    error. The linker will nonetheless complain if it cannot find the library,
    it just won't check for any symbols in that library.

    Tobias

    Tobias Peters Guest

  5. #4

    Default Re: Two problems creating a C++ extension to Ruby

    Hi Lyle,

    Lyle Johnson <lyle@knology.net> wrote in message news:<3F776A3F.5020300@knology.net>...
    > Matthew Miller wrote:
    >
    > > for the second argument the test fails. I've gotten around this by not doing
    > > a library test and just calling create_makefile and then editing the
    > > resulting makefile by hand to have the extension .so linked against
    > > libid3.so.
    >
    > Since libid3.so is not optional in this case, I think it is OK to just
    > assume that it's there. To avoid having to edit the Makefile, though,
    > try adding this line to your extconf.rb script before the final call to
    > create_makefile():
    >
    > $libs = append_library($libs, "id3")
    That works very well, thanks. It was also necessary for me to change
    one of the config values: CONFIG['LDSHARED'] = "g++ -shared"
    > > The second problem came up when I tried to test the extension. After
    > > creating a new ID3Lib object, which opens an mp3 file, the script calls the
    > > :artist method to return a string containing the value of that tag. That
    > > method call generates an ArgumentError exception with the error message
    > > "NULL pointer given".
    >
    > OK. So if we look at the extension code for the ID3Lib#artist method:
    >
    > static VALUE id3_get_artist( VALUE obj ) {
    > ID3Lib* id3 = static_cast<ID3Lib*>(DATA_PTR( obj ));
    > return rb_str_new2( id3->artist );
    > }
    >
    > This almost certainly indicates that the id3->artist field is a NULL
    > pointer. So it is the call to rb_str_new2() that is generating the "NULL
    > pointer given" error message.
    >
    > > I've tried to isolate where that error is generated and I can only say that
    > > it seems to come from within Ruby. Replacing the body of the C++ function,
    > > that is called for the no argument version of :artist, with a statement to
    > > return a Fixnum still results in the "NULL pointer given" exception. So it
    > > seems that the statements within id3_get_album() don't cause the exception,
    > > but maybe someother part of my C++ code is the problem?
    >
    > The C++ function that implements the ID3Lib#artist method is
    > id3_get_artist(), not id3_get_album(). You did indeed put some debugging
    > code in id3_get_album(), but that's not the one that's getting invoked
    > when you call ID3Lib#artist.
    Well, these comments got me started in the right direction. When
    reading the frames of the id3 tag I was using the wrong frame type
    constant for the artist's name frame. Fixing that and how the char*'s
    were initialized got everything working.
    > > If anyone can help, I would be very appreciative. If you look at the code, I
    > > am also open to comments and suggestions not related to the above problems.
    >
    > The code looks really good to me. I suspect that this is just a little
    > bug somewhere that you'll be able to fix without much trouble.
    Thanks Lyle, you're right. Once I got a fresh look at the code fixing
    it wasn't too much trouble. While this extension is still very beta,
    anyone can get the code here:
    [url]http://roland.sw.edu/matthew/id3lib_ext-fixed.tar.gz[/url] Once I've done
    more work I'll create a RAA entry...

    Lyle, again thanks for your help. I believe that nearly everytime I've
    had a Ruby or FXRuby question you have provided an answer or helped in
    some way. You have been a great help to me learning Ruby!

    Take care, Matthew.
    Matthew Miller Guest

Posting Permissions

  • You may not post new threads
  • You may post replies
  • You may not post attachments
  • You may not edit your posts

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139