cb921 has asked for the wisdom of the Perl Monks concerning the following question:

Understanding is paradigmatic, as I think I know something, perl changes that. It is with humility in my heart, and thankfulness towards those who have helped me this far, that I pose the silly question that is at the core of my struggle today. I was told, and have come to discover, that creating typemaps for an XS module was where the real difficulty lies. I have created a few of the functions, and the XS module is compiling and linking the vendor libs correctly (making a static perl fixed all problems, thanks tye, adam and others for a lot of good advice) Through no lack of searching, and a large enough lack of time to preclude the entire reading and absorbing of perlguts, I am unable to create a typemap that simply converts a variable of type struct* into a hash with keys named samewise, and vice versa. Can someone direct me to the place where I discover the purposes of $var and $arg? That does sound like the manpage I need. Any page I've found so far dealing with the typemap has assumed this was known. This isn't really a real question.. If anyone has wisdom, URL's, warnings, or some way to fit man perlguts into a not yet entirely conditioned head, I'm asking for your help. Thanks again, cb921.

Replies are listed 'Best First'.
(tye)Re: XS module typemap
by tye (Sage) on Oct 02, 2000 at 20:18 UTC

    $var is the name of the C variable for a particular funcion argument. $arg is the Perl SV that matches $var. So an "input" typemap sets $var to be some value based on $arg. An "output" typemap sets $arg based on $var. No, I don't recall where that is documented [ other than the source code :( so you might want to read bits of perl/lib/ExtUtils/*.pm from time to time ].

    I would not recommend doing C-struct-to-Perl-hash conversion (or vice versa) via a typemap for two reasons:

    1. You'd have to do the conversion once or twice per call and the performance penalty can easily be too high.
    2. This takes at least a few lines of C code and putting that much C code into a typemap is a pain and hard to maintain.

    I find it is better to keep C structs either "packed" into a Perl string if possible, or hidden in a Perl integer if necessary (as far as the XS interface is concerned). The first method is possible if the C code that you are interfacing to allows the caller to allocate the memory for the structs. The second method (or something similar or perhaps lots of memory copying) is required if the C API insists on passing back pointers to memory that it allocated itself.

    Then you can write pack/unpack and/or insert/extract routines (in XS and/or Perl) and probably provide one or more Perl wrappers that do the pack-then-call-XS-then-unpack to make things easy for certain cases.

    There are a ton of ways to write these pack/unpack and/or insert/extract routines. I'd probably have:

    $packed= mystructPack( \%unpacked ); $refToUnpacked= mystructUnpack( $packed );
    If you want more details then post more details like the specific struct and what you typically do with it.

    Also, buffers.h in Win32API::Registry includes some macros for dealing with typemaps of pointers to structs.

            - tye (but my friends call me "Tye")
Re: XS module typemap
by cb921 (Initiate) on Oct 04, 2000 at 21:55 UTC
    Still stupid questions.. I hate to do it, and I really appreciate your patience (so far).. The first more complex xsub I need, now looks like this (it's not terribly good, nor functional.. also some bad comment added):
    int dx_playf(chdev, fnamep) /* must put tpt here, and am .still. not clear + */ int chdev char *fnamep PREINIT: DV_TPT tptmp[2]; CODE: /* Will the constants below be worked out of the headers, which are included above in the XS? I've seen lots of ways of getting them to Perl, but perl does not need them */ tpt[0].tp_type = IO_CONT; /* the next entry is next on arr +ay */ tpt[0].tp_termno = DX_IDDTIME; /* Interdigit Delay */ tpt[0].tp_length = 2; tpt[0].tp_flags = TF_IDDTIME; tpt[1].tp_type = IO_EOT; /* last entry */ tpt[1].tp_termno = DX_MAXDTMF; /* Maximum digits to get from ca +ller */ tpt[1].tp_length = 1; tpt[1].tp_flags = TF_MAXDTMF; RETVAL = dx_playf(chdev, fnamep, tptmp, 0); OUTPUT: RETVAL
    The DX_TPT struct is defined in the header:
    typedef struct DV_TPT { unsigned short tp_type; /* Flags describing t +his entry */ unsigned short tp_termno; /* Termination Parame +ter number */ unsigned short tp_length; /* Length of terminat +or */ unsigned short tp_flags; /* Parameter attribut +e flag */ unsigned short tp_data; /* Optional additiona +l data */ unsigned short rfu; /* Reserved + */ DV_TPT *tp_nextp; /* Pointer to next te +rmination TPT */ }DV_TPT;
    and info on all the mad things I must still do with the DV_TPT at http://support.dialogic.com/documentation/unix/SR50_linux/html_files/vox_api/0009c-07-163.html#P18891_490358 This also doesn't have the code to make and destroy memory.. These are the things I still must learn, if I do disclose my experience by other means than my PM experience points.. I envisage wrapping the lot, so I need to make a setter for each type (no need for a getter, it's just for passing args in), correct? I have a problem now that all the simpler functions are failing. -1, and $! = Invalid Argument. the xsubs are:
    int dx_open(chdev, mode) const char * chdev int mode int dx_close(dev) int dev int dx_sethook(chdev, hookstate, mode) int chdev int hookstate unsigned short mode
    and the following lines in test.pl:
    $chdev = Starla::dx::dx_open("dxxxB1C1",0) or die "Cannot open dxxxB1 +C1 ($!)\n"; print "Device is $chdev ($!), state is "; $tmp = Starla::dx::ATDX_STATE($chdev); print "$tmp ($!)\n";
    returns: Device is -1 (Invalid argument), state is -1 (Invalid argument) At this point I wonder how I even managed to do this under some software package under Windows NT. This is about as complex as I will need to get, and feeling like even that's skew. Thanks again.. problem is probably due to a bit of a lack of sleep, which I plan to do now. THis is a learn for me, but if I can make it well enough, not only will I run my server using this extension, I also want to make it my first CPAN module