The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

HACKERS - Devel::PPPort internals for hackers

SYNOPSIS

So you probably want to hack Devel::PPPort?

Well, here's some information to get you started with what's lying around in this distro.

DESCRIPTION

How to build 87 versions of perl

Devel::PPPort supports Perl versions between 5.003 and bleadperl. To guarantee this support, I need some of these versions on my machine. I currently have 87 different Perl version/configuration combinations installed on my laptop.

As many of the old Perl distributions need patching to compile cleanly on newer systems (and because building 87 perls by hand just isn't fun), I wrote a tool to build all the different versions and configurations. You can find it in devel/buildperl.pl.

Fully automatic API checks

Knowing which parts of the API are not backwards compatible and probably need Devel::PPPort support is another problem that's not easy to deal with manually. If you run

    perl Makefile.PL --with-apicheck

a C file is generated by parts/apicheck.pl that is compiled and linked with Devel::PPPort. This C file has the purpose of using each of the public API functions/macros once.

The required information is derived from parts/embed.fnc (just a copy of bleadperl's embed.fnc) and parts/apidoc.fnc (which is generated by devel/mkapidoc.sh and simply collects the rest of the apidoc entries spread over the Perl source code). The generated C file apicheck.c is currently about 500k in size and takes quite a while to compile.

Usually, apicheck.c won't compile with older perls. And even if it compiles, there's still a good chance of the dynamic linker failing at make test time. But that's on purpose!

We can use these failures to find changes in the API automatically. The two Perl scripts devel/mktodo and devel/mktodo.pl repeatedly run Devel::PPPort with the apicheck code through all different versions of perl. Scanning the output of the compiler and the dynamic linker for errors, the files in parts/todo/ are generated. These files list all parts of the public API that don't work with less than a certain version of Perl.

This information is in turn used by parts/apicheck.pl to mask API calls in the generated C file for these versions, so the process can be stopped by the time apicheck.c compiles cleanly and the dynamic linker is happy. (Actually, this process generates false positives, so each API call is checked once more afterwards.)

Running devel/mktodo takes a couple of hours.

Implementation

Residing in parts/inc/ is the "heart" of Devel::PPPort. Each of the files implements a part of the supported API, along with hints, dependency information, XS code and tests. The files are in a POD-like format that is parsed using the functions in parts/ppptools.pl.

The scripts PPPort_pm.PL, PPPort_xs.PL and mktests.PL all use the information in parts/inc/ to generate the main module PPPort.pm, the XS code in PPPort.xs and various test files in t/.

All of these files could be generated on the fly while building Devel::PPPort, but not having the tests in t/ and not having PPPort.xs will confuse Configure and TEST/harness in the core. Not having PPPort.pm will be bad for viewing the docs on search.cpan.org. So unfortunately, it's unavoidable to put some redundancy into the package.

Adding stuff to Devel::PPPort

First, check if the code you plan to add fits into one of the existing files in parts/inc/. If not, just start a new one and remember to include it from within PPPort_pm.PL.

Each file holds all relevant data for implementing a certain part of the API:

  • A list of the provided API in the =provides section.

  • The implementation to add to ppport.h in the =implementation section.

  • The code required to add to PPPort.xs for testing the implementation. This code goes into the =xshead, =xsinit, =xsmisc, =xsboot and =xsubs section. Have a look at the template in PPPort_xs.PL to see where the code ends up.

  • The tests in the =tests section. Remember not to use any fancy modules or syntax elements, as the test code should be able to run with Perl 5.003, which, for example, doesn't support my in for-loops:

        for my $x (1, 2, 3) { }    # won't work

    You can use ok() to report success or failure.

It's usually the best approach to just copy an existing file and use it as a template.

Special Makefile targets.

You can use

    make regen

to regenerate all of the autogenerated files. To get rid of all generated files (except for parts/todo/*), use

    make purge_all

That's it.

COPYRIGHT

Version 3.x, Copyright (C) 2004, Marcus Holland-Moritz.

Version 2.x, Copyright (C) 2001, Paul Marquess.

Version 1.x, Copyright (C) 1999, Kenneth Albanowski.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

SEE ALSO

See ppport.h.