Problem wrapping a class with rbplusplus
Closed this issue · 7 comments
I am trying to wrap a class (goblinController) in the goblin library (http://goblin2.sourceforge.net/), and I get this error from rbgccxml:
ruby wrapper.rb --clean
(INFO) Parsing ["/Users/papipo/Projects/goblin/src/goblin_wrapper.h"]
(INFO) Beginning code generation
(INFO) Wrapping class goblin::goblinController
(WARNING) goblin::goblinController has multiple constructors. While the extension will probably compile, Rice only supports one constructor, please use #use_contructor to select which one to use.
(INFO) Wrapping class goblin::biGraph
(INFO) Code generation complete
(INFO) Writing code to files
/usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/builders/method_base.rb:165:in `fix_enumeration_value': undefined method `first' for #<RbGCCXML::EnumValue:0x000001045d5598> (NoMethodError)
from /usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/builders/method_base.rb:121:in `block in wrap_normal_method'
from /usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/builders/method_base.rb:115:in `each'
from /usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/builders/method_base.rb:115:in `wrap_normal_method'
from /usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/builders/method_base.rb:38:in `write'
from /usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/writers/single_file_writer.rb:45:in `process_code'
from /usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/writers/single_file_writer.rb:60:in `block in process_code'
from /usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/writers/single_file_writer.rb:59:in `each'
from /usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/writers/single_file_writer.rb:59:in `process_code'
from /usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/writers/single_file_writer.rb:60:in `block in process_code'
from /usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/writers/single_file_writer.rb:59:in `each'
from /usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/writers/single_file_writer.rb:59:in `process_code'
from /usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/writers/single_file_writer.rb:60:in `block in process_code'
from /usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/writers/single_file_writer.rb:59:in `each'
from /usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/writers/single_file_writer.rb:59:in `process_code'
from /usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/writers/single_file_writer.rb:20:in `write'
from /usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/extension.rb:219:in `write'
from /usr/local/Cellar/ruby/1.9.2-p290/lib/ruby/gems/1.9.1/gems/rbplusplus-1.0.1/lib/rbplusplus/extension.rb:84:in `initialize'
from wrapper.rb:52:in `new'
from wrapper.rb:52:in `<main>'
Very strange, I'll check out what's going on. Do you have the download link for goblin? I keep getting a Sourceforge error page when I try to download the library's source.
http://sourceforge.net/projects/goblin2/files/latest/download?source=files
Put "lib_src" and "include" dirs in a local "src" dir and use this as wrapper:
require 'rbplusplus'
SRC = File.expand_path(File.join(File.dirname(__FILE__), 'src'))
def constructor_for(klass, arguments = 0)
klass.use_constructor(klass.constructors.find(arguments: Array.new(arguments.to_i)))
end
def constructors_for(klass, options)
options.each_pair { |name,arguments| constructor_for(klass.classes(name), arguments) }
end
def structs(klass, options)
options.each_pair { |name,arguments| constructor_for(klass.structs(name), arguments) }
end
File.open("#{SRC}/goblin_wrapper.h", "w") do |file|
file.puts <<-SRC
#ifndef GOBLIN_WRAPPER_H
#define GOBLIN_WRAPPER_H
#include <climits>
#include <cfloat>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <exception>
#include <new>
#include <list>
#include <vector>
#include <limits.h>
#include <stdlib.h>
namespace goblin {
#define _GOBLIN_MAJOR_VERSION_ 2
#define _GOBLIN_MINOR_VERSION_ 8
#define _GOBLIN_REVISION_ "b28"
#include "goblin.h"
#{Dir["#{SRC}/lib_src/*.cpp"].map { |cpp| "#include \"#{File.basename(cpp)}\""}.join("\n")}
}
#endif
SRC
end
RbPlusPlus::Extension.new("goblin") do |e|
e.writer_mode :single
e.working_dir = 'ext/goblin'
e.sources ["#{SRC}/goblin_wrapper.h"], include_paths: ["#{SRC}/include", "#{SRC}/lib_src"]
e.module "Goblin" do |goblin|
node = goblin.namespace "goblin"
node.functions.ignore
node.enumerations.ignore
node.classes.ignore
node.structs.ignore
node.classes("biGraph").tap do |bigraph|
bigraph.unignore
bigraph.wrap_as("BiGraph")
constructor_for(bigraph, 3)
end
node.classes("goblinController").tap do |goblin_controller|
goblin_controller.unignore
# goblin_controller.wrap_as("GoblinController")
# constructor_for(controller, 1)
end
end
end
lines = File.readlines("ext/goblin/goblin.rb.cpp")
File.open("ext/goblin/goblin.rb.cpp", "w") do |file|
lines.each do |line|
next if line.match(/BackCast|back_cast|sparseBigraph\.h/)
file.puts line
end
end
Check out the last lines where I remove header files that rbplusplus adds before goblin_wrapper.h
Is there a way to avoid them so I don't need to remove them?
A couple of things I've noticed so far:
- Your custom wrapper file should not be including .cpp files, and from what I see it should only need "goblin.h" to pull in all the appropriate header files in the library.
- Only pulling in goblin.h does cause some problems, in that it has some
operator new
andoperator deletes
defined, which apparently cannot be put in a namespace. I was unable to get HEAP_MON undefined, so I commented them out. - That led me to biGraph, which I was unable to find anywhere in the code (but it is in doku/manual.tex?). Is this supposed to be abstractBiGraph?
GCC-XML was never meant to parse C++ object bodies, only the headers and definitions of objects, and as such rb++ can only work with C++ header information. Pulling in the cpp files may have caused some confusion that led to this odd EnumValue error (that I so far have been unable to reproduce).
For the HEAP_MON stuff you must tweak configuration.h. I think I generated that file by running ./configure.
BTW, I just removed the cpp includes here and I still get the EnumValue error :-/
Ok I found out what's going on here. Commit d6474de has the answer. Enumeration#children was changed to return a QueryResult, which has a side effect of returning the object if there's only one in the list. I should revert this change as you'll always want a raw array of EnumValues to work with (and is exactly what rb++ expects to happen). Looking through the goblin code I've found a few enums that have only one value in it, which is what would throw this error.
I'll get rbgccxml changed and a new gem pushed, should fix this issue.
Ok further diving into what's up here, I decided to update rb++ instead of changing rbgccxml back. The error was with arguments with default values that included a single-value enumeration. Grab the newest version of rb++ (1.0.3) and let me know if this works better for you.
It seems to fix this very issue. Now I've new stuff to handle, thanks :D