chicken-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Chicken-users] Chicken foreign type to SWIG type


From: John Lenz
Subject: Re: [Chicken-users] Chicken foreign type to SWIG type
Date: Wed, 15 Dec 2004 20:29:18 +0000

On 12/15/04 00:24:16, felix winkelmann wrote:
> On Tue, 14 Dec 2004 21:41:15 +0000, Joel Reymont <address@hidden> wrote:
> > Folks,
> > 
> > Is there a simple way of converting between Chicken's foreign type and a
> > SWIG type? I have a library (guichan) that I wrapped with SWIG. This
> > library uses SDL. I tried using the SDL egg with it but it does not work.
> > 
> >[...]
> > 
> > but SWIG would expect something like _p_SDL_Surface.
> > 
> > Any suggestions apart from creating another SDL wrapper for Chicken?
> > 
> 
> Hm, I don't know how SWIG represents it's data. Perhaps John can give us
> a suggestion here? Getting the SDL_Surface pointer out of the SDL
> surface record is easy, we just have to know how to wrap it.
> 

It's a tough problem.  If you want to just bypass the SWIG type system,
C_block_item(x, 0) will give you the void pointer...

So something like (foreign-lambda swig-surface "extract_sdl_surface" C_word)
where extract_sdl_surface just returned C_block_item(x,0).... don't know
if that is valid, but...

A better approach would be to do the type checking.

What SWIG does is store two pointers, one the void * of the object and the 
second a pointer to a swig_type_info structure which describes information 
about what type the void * is, and what types it can cast into.  It also 
includes a function to do the casting between different types.  

For a complete description on what these structures are, read the Details 
section 8.8.1 on my web site
http://www.cs.wisc.edu/~lenz/swig.html
(Note: that patch will probably be going into SWIG during the 1.3.25 
release cycle, so this is the way it will work in the future.  The way it 
works now is very similar.)

So in any case, SWIG allows external files or user written files 
to interact with its type system.  The way this works is that any code 
that wants to interact with the type system would

#include <swigrun.swg>
#include <chicken/chickenrun.swg>
#include <runtime.swg>

(These files are located in the Lib directory in SWIG)

Once those files are included, the following functions would be available.

swig_type_info *SWIG_TypeQuery(char *name);
If returns NULL, then the type name was not found.

C_word SWIG_Chicken_NewPointerObj(void *ptr, swig_type_info *type, int owner, 
C_word **space);
Here, owner == 1 if chicken owns this pointer (that is, when chicken 
collects this, we should call the destrutor and delete it).
space should point to at least C_SIZEOF_SWIG_POINTER

void *SWIG_MustGetPtr(C_word obj, swig_type_info *type, int argnum, int flags);
This function extracts the pointer from obj, correctly casting it for
multiple inheritance and such.  It extracts the swig_type_info from obj,
and compares it with the swig_type_info passed to the function to see if
they are compatible.  flags is ignored (it is there so the different
language modules in SWIG have the same interface (note, we break this with
NewPointerObj because we need that extra argument space...)).

If the type can not be converted, it panics (via a call to C_halt) and prints a 
message like
"Type error in argument ,argnum: expected a ,type->name."
Alternativly, you can call SWIG_ConvertPtr to not print a message on failure.
int SWIG_ConvertPtr(C_word s, void **result, swig_type_info *type, int flags)
returns 0 on success, 1 on failure.

In any case, I think one way to solve this would be for chicken to export and
use these functions.  That is, after some argument or (declare) or something,
chicken would, inside the stub call which currently looks like
/* from k86 */
static C_word C_fcall stub19(C_word C_buf,C_word C_a0) C_regparm;
C_regparm static C_word C_fcall stub19(C_word C_buf,C_word C_a0){
C_word C_r=C_SCHEME_UNDEFINED,*C_a=(C_word*)C_buf;
SDL_Surface *t0=(SDL_Surface *)C_c_pointer_or_null(C_a0);
C_r=C_fix((C_word)hey(t0));
return C_r;}

We could do something like
swig_type_info *t = SWIG_TypeQuery("SDL_Surface *");
void *ptr;
SDL_Surface *t0;
if (!t || SWIG_ConvertPtr(C_a0, &ptr, t, 0)) {
  t0 = (SDL_Surface *)C_c_pointer_or_null(C_a0);
} else {
  t0 = (SDL_Surface *)ptr;
}
C_r = C_fix((C_word)hey(t0));

and for returning a pointer,
/* from bob2 in k78 in k45 in k42 in k39 */
static C_word C_fcall stub24(C_word C_buf) C_regparm;
C_regparm static C_word C_fcall stub24(C_word C_buf){
C_word C_r=C_SCHEME_UNDEFINED,*C_a=(C_word*)C_buf;
C_r=C_mpointer_or_false(&C_a,(void*)hey2());
return C_r;}

we might have to export two functions, one that looks like this
that returns a mpointer, and a second that looks something like
C_r=C_SCHEME_UNDEFINED,*C_a=(C_word*)C_buf;
swig_type_info *t = SWIG_TypeQuery("SDL_Surface *");
if (t) {
  C_r=SWIG_Chicken_NewPointerObj((void*)hey2(), t, ??, &a);
} else {
  stub24(C_buf);
}

Heh, here we see the problem... what to stick for the ??.  Probably should
just be 0, meaning that when the swigpointer is destroyed, nothing happens
to the underlying pointer.

The only problem would be that the egg would have to be built with this
stuff in it.

One option would be to export the code into the egg, but guard it with
#ifdef ACCEPT_SWIG_POINTERS or something, so when compiling the egg, if the
user has the headers avaiable (SWIG installed), ACCEPT_SWIG_POINTERS can be
defined and the egg would accept swig pointers.  Possibly even check in the
.setup file

The good news is that the three header files included above
can just be copied into the egg.  The header files actually contain all
the functions declared static.  So even though you are including header
files from swig, there are no external files or libraries you need to link
to.  All functions are declared static, and TypeQuery uses that SWIG_GetModule
function I was talking about in that other thread.  Thus, the functions
are replicated in every module, but they all communicate using that pointer
stored in that symbol table.  Thus it should be possible to just copy those
three header files, and then to build the egg wouldn't even require SWIG to
be installed.

If you do it this way, it would allow the somewhat sick
class Foo {
public: int a;
};
class Bar {
public: int b;
};
class FooBar : public Foo, public Bar {
public: int c;
};

(define-foreign-type Bar (pointer "Bar")
  bar-pointer
  make-bar)

(define hey (foreign-lambda int "hey" Bar))
(hey (new-FooBar)) ;; where new-FooBar is the function created by SWIG

but would also catch type errors.

John





reply via email to

[Prev in Thread] Current Thread [Next in Thread]