One of the C interfaces has a signature like this:
char *foo(char *buf, size_t n);
I.e. it's an old-fashioned function where the caller is expected to
allocate and pass in a construction buffer and the length of said buffer
and foo() will fill it in. Just like getcwd(), for instance. And also
as with getcwd you can pass in NULL as your buffer, which will cause it
to malloc the appropriate space and return it. Thus the caller can take
all responsibility for memory management or delegate it (the creation
side, at least) to the API. But this gets a lot more complicated when
calling through a Perl/C barrier, since they each have very different
memory-management philosophies. My problem comes in a few pieces:
1. First, I can't figure out how to create a reference to allocated,
uninitialized space in perl for passing through the SWIG wrapper into
foo(). Not that I necessarily want to handle it this non-perlish way
but I'd like to find out if it's possible. Any ideas?
2. Similarly, I don't want my perl wrapper code to take advantage of the
"pass in NULL, get malloc-ed space back" capability since that memory
would presumably never be freed, but I'm wondering how to do it. The
Perl5 section of the SWIG user manual says that to pass NULL into a C
function you should use 'undef' but this causes a core dump for me.
Passing 0 is rejected by the SWIG layer as a type mismatch. Does anyone
know how to pass NULL into a C function from Perl via SWIG wrappers?
3. The hack I'm currently using is an intermediary C function:
char *foo_prime(void) { return foo(NULL, 0); }
This dodges the interface problems but of course at the cost of a memory
leak, not to mention ugly code. What I really want to do is find a way
to get all the memory management under control of Perl so things can be
easier for the programmer - which is, after all, the point of using Perl
in the first place. So any big-picture ideas or RTFMs on how this is
best handled are welcomed.
PS Don't worry, I'm not exposing this C-ish construction buffer
technology to the module user; I'd just prefer to leave the C library
more or less alone and hide the C-ness of it in the module code. There
are really two layers of "wrapper" code here: the SWIG-generated
wrappers which define a one-to-one mapping of C functions to perl
subroutines, plus a layer of perl code to wrap all of that into a nice
perly interface.
Thanks,
David Boyce
> 1. First, I can't figure out how to create a reference to allocated,
> uninitialized space in perl for passing through the SWIG wrapper into
> foo(). Not that I necessarily want to handle it this non-perlish way
> but I'd like to find out if it's possible. Any ideas?
>
+Sounds+ like you want (wait for it...) a typeglob or a reference to an
anonymous array
.. or somesuch. I can only say that because I've just read Sriran
Srinivasan's
wonderful "Advanced Perl Programming", which I heartily recommend to
all!
Thus:
$buf = [];
creates an empty anonymous array and returns a reference to it,
while:
$buf = [ 0,0,0,0];
creates an initialised anonymous array and returns a reference to it.
In both instances, the array itself doesn't have a "name" but "$buf" is
a hook to it, and acts effectively, as a "pointer" to an
(already-malloced)
unnamed array. Later, if you need to expand the array, via its
reference, just "purporting" to add an entry or more will get you the
extra memory.
You can pass in the reference to a subroutine in perl and then
access its contents via "the extra dollar" mechanism... Thus:
$$buf refers to the data pointed to by a scalar reference.
@$buf refers to the data pointed to by an array reference
...etc.
Similarly, you can use a "typeglob", which is a pointer "sort-of",
or a "sort-of" pointer... It actually is more versatile than a
C pointer..
You can do something like this:
$buf = []; # create reference to uninitialised anonymous array
foo( *buf); # call a subroutine passing a typeglob for the array
...
sub foo {
*mbuf = shift;
push(@mbuf, "data"); # use the dereference to add data to the array
Now... I +think+ I've got that right... but check it. :-)
> 2. Similarly, I don't want my perl wrapper code to take advantage of the
> "pass in NULL, get malloc-ed space back" capability since that memory
> would presumably never be freed, but I'm wondering how to do it.
But if you use a reference, perl knows when a reference is effectively
out of scope...it keeps a reference counter in its data structures
and frees automagically when the reference count goes down to zero...
The
> Perl5 section of the SWIG user manual says that to pass NULL into a C
> function you should use 'undef' but this causes a core dump for me.
> Passing 0 is rejected by the SWIG layer as a type mismatch. Does anyone
> know how to pass NULL into a C function from Perl via SWIG wrappers?
Pass..
> 3. The hack I'm currently using is an intermediary C function:
>
> char *foo_prime(void) { return foo(NULL, 0); }
>
> This dodges the interface problems but of course at the cost of a memory
> leak, not to mention ugly code. What I really want to do is find a way
> to get all the memory management under control of Perl so things can be
> easier for the programmer - which is, after all, the point of using Perl
> in the first place. So any big-picture ideas or RTFMs on how this is
> best handled are welcomed.
Go for the book: it's published by O'Reilly. It's got stuff on the
C interface and embedding, which I'm only just starting to struggle
with. I think it'll help, though.
--
Peter G. Martin, Tech Writer, Perl user
pet...@zeta.org.au ph: +61 2 9818-5094
http://www.zeta.org.au/~peterm
> I have a C API (for which I own the source, BTW) and am trying to embed
> it into a Perl module using SWIG. And it all works fine, in fact,
> except for one problem which I've hacked around. I'm unhappy with the
> hack and that's what I'm looking for help with.
>
> One of the C interfaces has a signature like this:
>
> char *foo(char *buf, size_t n);
>
> I.e. it's an old-fashioned function where the caller is expected to
> allocate and pass in a construction buffer and the length of said buffer
> and foo() will fill it in. Just like getcwd(), for instance. And also
> as with getcwd you can pass in NULL as your buffer, which will cause it
> to malloc the appropriate space and return it. Thus the caller can take
> all responsibility for memory management or delegate it (the creation
> side, at least) to the API. But this gets a lot more complicated when
> calling through a Perl/C barrier, since they each have very different
> memory-management philosophies. My problem comes in a few pieces:
>
> 1. First, I can't figure out how to create a reference to allocated,
> uninitialized space in perl for passing through the SWIG wrapper into
> foo(). Not that I necessarily want to handle it this non-perlish way
> but I'd like to find out if it's possible. Any ideas?
Use the array and pointer library provided with SWIG :
Here's an example from my own perl-C interface:
$num_cnx = ptrcreate("int",16) ;
$cnx_int_array = int_array(16) ; # create C array
> 2. Similarly, I don't want my perl wrapper code to take advantage of the
> "pass in NULL, get malloc-ed space back" capability since that memory
> would presumably never be freed, but I'm wondering how to do it. The
> Perl5 section of the SWIG user manual says that to pass NULL into a C
> function you should use 'undef' but this causes a core dump for me.
> Passing 0 is rejected by the SWIG layer as a type mismatch. Does anyone
> know how to pass NULL into a C function from Perl via SWIG wrappers?
'undef' works fine with SWIG 1.1p2, the core dump probably occurs in or below
foo or your SWIG version is old.. (Have you checked where the core dump
occurs ?)
> 3. The hack I'm currently using is an intermediary C function:
>
> char *foo_prime(void) { return foo(NULL, 0); }
>
> This dodges the interface problems but of course at the cost of a memory
> leak, not to mention ugly code. What I really want to do is find a way
> to get all the memory management under control of Perl so things can be
> easier for the programmer - which is, after all, the point of using Perl
> in the first place. So any big-picture ideas or RTFMs on how this is
> best handled are welcomed.
You can create C array in Perl using the array and pointer library provided
with SWIG. Check SWIG manual.
BTW, you should post these kind of question to the swig mailing list
(Check http://www.cs.utah.edu/~beazley/SWIG/)
Hope this helps