From: Lyle Johnson Date: 2003-09-29T08:13:14+09:00 Subject: 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(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