Thanks to Sisyphus and muppet for the pointer to perlxstut Example #4. It's funny, I went through that tutorial back in May or June, even typing in all the example code. But it seems I didn't retain the bits I didn't understand.

On Nov 8, 2005, at 8:59 PM, muppet wrote:
dirty: write your extra C and H files. include them in MANIFEST. #include them from your xs code's verbatim C section.

Most of the code I'm talking about needs to be #include-d anyway:

1) Wrapper functions around PerlIO_xxxxx, e.g. KinoIO_read_vint below
2) typedefs and init/manip/destroy routines for the new types
3) global constants, e.g. "#define A_GLOBAL_CONSTANT 255"
4) Utilities, e.g. Kino_confess which allows Carp::confess to be invoked from C a la the sprintf croak/warn.

All that stuff is supposed to be accessible throughout the amalgamated KinoSearch.xs -- it's dirty by design. But it makes sense to break it up into a few C modules, e.g. KinoIO.h/KinoIO.c.

... [ time passes while Marvin experiments ] ...

Hey wait a minute... you're going to need to #include at least one of the .h files in the .xs file regardless, aren't you? Otherwise there's no way to get at the stuff in the compiled libraries from Perl. So I take it what you're calling "dirty" is the *absence* of more rigorous steps, not the mere existence of an #include directive in the verbatim C section of the .xs file.

proper: follow the example of EXAMPLE 4 in perlxstut, and build a little library for yourself, which you link in. c.f. L<perlxstut>

OK, ultimately, this is what I settled on. But I had to pass through the other stages before I understood enough to make it work. Didn't know what make did, didn't know what ar or ranlib did... I could do decent enough memory management to write a multi-field mergesort algo with a bunch of pointer acrobatics and not leak, but I knew next to nothing about compiling! That's where starting off with Inline::C gets ya.

quick and just as good: add your extra files' names to MANIFEST so that they get dirstributed, and add extra object files to the OBJECT key to WriteMakefile, like so:

   WriteMakefile (
      ...
      OBJECT => q[$(BASE_EXT)$(OBJ_EXT) myextracfile$(OBJ_EXT)],
      ...
   );

Worked like a charm, once I got all my .c/.h files sorted out and figured out how to use include guards to stop those redefinitions... that is, until I tried to tidy up and move the new files into a src/ directory. boom!

Note that you are overwriting the default for OBJECT, so we supply that default manually -- that's what $(BASE_EXT)$(OBJ_EXT) is. You specify only the object file version of your filename -- for myextracfile.c you'd specify myextracfile$(OBJ_EXT), which gets expanded to myextracfile.o or myextracfile.obj or whatever is correct for the platform; the make rules can figure out that this needs to be built from a c file with the same name. See L<ExtUtils::MakeMaker> for more info -- search for OBJECT.

An excellent explanation.  Thanks.

Make is actually quite easy, once you understand how it does bookkeeping.

This was useful to know. Between Make's rep as "evil" due to the tab/ space issue and hearing Michael Schwern (maintainer of MakeMaker) let off steam about MakeMaker at Portland Perl Mongers meetings, I had gotten the impression that it was much more complex than it actually turns out to be.

This was the best of the various overviews I stumbled across while googling:

http://www.cprogramming.com/tutorial/makefiles.html

Cheers,

Marvin Humphrey
Rectangular Research
http://www.rectangular.com/

/**************************************************************/

/* read in a Variable INTeger, stored in 1-5 bytes */
U32
KinoIO_read_vint (PerlIO *fh) {
    unsigned char   aUChar;
    int             bitshift;
    int             check_val;
    U32             aU32;

    /* start by reading one byte; use the lower 7 bits */
    check_val = PerlIO_read(fh, &aUChar, 1);
    if (check_val < 1)
        Kino_confess("KinoIO_read_vint error: %d", check_val);

    aU32 = aUChar & 0x7f;

    /* keep reading and shifting as long as the high bit is set */
    for (bitshift = 7; (aUChar & 0x80) != 0; bitshift += 7) {
        check_val = PerlIO_read(fh, &aUChar, 1);
        if (check_val < 1)
            Kino_confess("KinoIO_read_vint error: %d", check_val);
         aU32 |= (aUChar & 0x7f) << bitshift;
    }
    return aU32;
}

Reply via email to