On Thu, Nov 1, 2012 at 11:08 PM, Logan Bell <[email protected]> wrote:
> To summarize this is where we're at in regard to binding ruby to Lucy:
>
> 1. We have a rakefile clownfish/runtime/ruby that builds builds lemon,
> clownfish, and CFC.c in the ext folder. This CFC.c contains bindings for
> Ruby for the following clownfish objects: Clownfish::CFC::Model::Hierarchy
> and Clownfish::CFC::Binding::Core.
>
> 2. We also have a rakefile in clownfish/compiler/ruby that invokes the
> aforementioned runtime rake file, builds charmonizer and the ruby
> charmonizer.rb file, and invokes the Clownfish::CFC::Model::Hierarchy
> and Clownfish::CFC::Binding::Core ruby objects to generate the autogen
> folder. This rakefile also builds, utilizing Rake::ExtensionTask, the Bind
> code in the ext folder which contain routines to convert Clownfish
> charbufs/varrays to ruby objects.
Nice work. :)
FWIW, recent changes to CFCVersion.h have broken the Ruby build -- we started
pound-including "charmony.h" (which isn't there) rather than "stdint.h".
Thus, the very next step will be to integrate Charmonizer.
That will involve compiling clownfish/compiler/common/charmonizer.c and
running the resulting executable to produce charmony.h (see the "charmony"
task in ruby/Rakefile), and then adding some include dirs to feed charmony.h
to CFCVersion.h.
> 3. There is also a Rakefile in root/ruby that I believe is compiling Lucy
> itself. After taking a cursory glance at it appears to do be compiling
> charmonizer and clownfish too, so I think this build script may need to be
> revisited and/or refactored at a later point.
>
> With my limited scope and understanding, I believe going forward the next
> logical step would be to start creating a Clownfish::CFC::Binding::Ruby
> that implements a write_ext_typemap method which in turn would call out to
> CFCRubyTypeMap_write_ext_typemap.
The purpose of CFCPerlTypeMap_write_ext_typemap() function is to create the
file named "typemap" needed by Perl's XS compiler, xsubpp. I've had limited
experience with the Ruby C API, but to the best of my knowledge there's no
file which is analogous to "typemap".
The xsubpp compiler uses "typemap" when it compiles "Foo.xs" to "Foo.c"
For instance, consider the following XS function[1]:
lucy_Obj*
fetch(self, tick)
lucy_VArray *self;
uint32_t tick;
CODE:
RETVAL = Lucy_VA_Fetch(self, tick);
OUTPUT: RETVAL
It needs to convert a `lucy_VArray*` from Perl to C on input, and then convert
a `lucy_Obj*` return value into something Perl can deal with on output . To
determine how it does that, it uses the following entries from the typemap
file:
LUCY_VARRAY_
$var = (lucy_VArray*)XSBind_sv_to_cfish_obj($arg, LUCY_VARRAY, NULL);
...
LUCY_OBJ_
$arg = (SV*)Cfish_Obj_To_Host((cfish_Obj*)$var);
Here's the C code which xsubpp spits out; if you look close, you can see where
the typemap entries were used:
XS(XS_Clownfish__VArray_fetch); /* prototype to pass -Wmissing-prototypes */
XS(XS_Clownfish__VArray_fetch)
{
dXSARGS;
if (items != 2) {
croak_xs_usage(cv, "self, tick");
}
{
lucy_VArray * self =
(lucy_VArray*)XSBind_sv_to_cfish_obj(ST(0), LUCY_VARRAY, NULL);
uint32_t tick = (uint32_t)SvUV(ST(1));
lucy_Obj * RETVAL;
#line 3813 "lib/Clownfish.xs"
RETVAL = Lucy_VA_Fetch(self, tick);
#line 4325 "lib/Clownfish.c"
ST(0) = (SV*)Cfish_Obj_To_Host((cfish_Obj*)RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
To the best of my knowledge, Ruby doesn't have anything like "typemap" --
because Ruby extensions are written directly in C, and there's no intermediate
stage like a .xs file to be compiled by something like xsubpp.
Therefore, I don't think we will need write_ext_typemap(). HOWEVER...
If you look at CFCPerlTypeMap.h, there are three functions:
/** Return an expression which converts from a Perl scalar to a variable
* of the specified type.
*
* @param type A Clownfish::CFC::Model::Type, which will be used to select
* the mapping code.
* @param xs_var The C name of the Perl scalar from which we are
* extracting a value.
*/
char*
CFCPerlTypeMap_from_perl(struct CFCType *type, const char *xs_var);
/** Return an expression converts from a variable of type `type` to a Perl
* scalar.
*
* @param type A Clownfish::CFC::Model::Type, which will be used to select
* the mapping code.
* @param cf_var The name of the variable from which we are extracting a
* value.
*/
char*
CFCPerlTypeMap_to_perl(struct CFCType *type, const char *cf_var);
/** Auto-generate a "typemap" file that adheres to the conventions
* documented in "perlxs".
*
* We generate this file on the fly rather than maintain a static copy
* because we want an entry for each Clownfish type so that we can
* differentiate between them when checking arguments. Keeping the
* entries up-to-date manually as classes come and go would be a pain.
*
* @param hierarchy A Clownfish::CFC::Model::Hierarchy.
*/
void
CFCPerlTypeMap_write_xs_typemap(struct CFCHierarchy *hierarchy);
We need to adapt the first two routines for Ruby (but not the third).
Marvin Humphrey
[1] This XS code ought to work fine, but it's not what we actually use; I took
some liberties and cleaned it up a bit for the purposes of illustration.