Prepare a Pure-Perl Module for CPAN with h2xs
You will finish with a small, testable Perl module distribution skeleton, a first test command, and a safe path to making a release tarball. The workflow uses h2xs, which is included with Perl, and keeps uploading to CPAN as a separate decision.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow 30 to 60 minutes for the skeleton and first test. You need Perl 5.38.2 or a compatible Perl installation, a shell, and a working directory where you can create files. The examples use the locally installed h2xs 1.23 from Perl 5.38.2. The third-party module-starter command described by perlnewmod is not installed here, so this guide uses the bundled alternative.
Checkpoint
Stop after any numbered step. Your working directory should still contain only the files you expect, and no command in this guide needs root privileges.
1. Decide that the code is a module
Start with code that has a general interface rather than a one-off local data format. Search CPAN before choosing a name: a nearby module may already solve the problem, or may establish a naming pattern that users will expect. The local manual points to MetaCPAN for this check.
Choose a title-cased package name with a useful hierarchy. In the example, Demo::Greeting becomes a module file at lib/Demo/Greeting.pm. Replace it with your real name only after checking that it is not confusingly close to an existing distribution.
$ perl -v
$ h2xs --version
h2xs 1.23
$ command -v h2xs
/usr/bin/h2xs
The exact Perl patch level and executable path may differ. Keep the version output with your project notes because generated files and compatibility defaults can vary between Perl releases.
2. Generate a pure-Perl skeleton
Create the distribution in a new parent directory. The option combination below tells h2xs to omit Autoloader and XS material, skip the default Exporter code, use Test::More, and name the extension.
$ mkdir -p ~/src/perl-modules
$ cd ~/src/perl-modules
$ h2xs -AX --skip-exporter --use-new-tests -n Demo::Greeting
Writing Demo-Greeting/lib/Demo/Greeting.pm
Writing Demo-Greeting/Makefile.PL
Writing Demo-Greeting/README
Writing Demo-Greeting/t/Demo-Greeting.t
Writing Demo-Greeting/Changes
Writing Demo-Greeting/MANIFEST
The command creates a directory named after the package, with hyphens separating the hierarchy. It does not install the module and does not upload anything. If the directory already exists, stop and inspect it rather than adding -O casually: overwriting generated content can discard work.
Checkpoint
Confirm that the expected layout exists before editing it:
$ find Demo-Greeting -maxdepth 2 -type f -print | sort
Demo-Greeting/Changes
Demo-Greeting/MANIFEST
Demo-Greeting/Makefile.PL
Demo-Greeting/README
Demo-Greeting/t/Demo-Greeting.t
The module file is one directory deeper, so inspect it directly with find Demo-Greeting/lib -type f -print.
3. Replace the stubs with a small interface
Read the generated module and test before changing them. Keep use strict and use warnings enabled. A distributable module must be safe under callers' warning and strict settings, because you do not control the surrounding program.
For a first pass, implement one narrow function in Demo-Greeting/lib/Demo/Greeting.pm and call it from the generated test. Use Carp when the caller supplied invalid input: croak reports the caller's location, while die remains appropriate for a fault inside the module itself. Do not export every function by default. If you later offer imports, prefer an explicit opt-in list such as @EXPORT_OK and document it.
Keep user-facing explanations in POD in the module. Include a synopsis, the public interface, arguments, return values, failures, and a short example. Keep developer notes as Perl comments. The generated README is also part of the distribution: rewrite it so a reader can understand what the module does without opening its source.
4. Make the tests prove behaviour
Extend the generated t/Demo-Greeting.t beyond a compile check. Test normal input, a boundary case, and the failure path you documented. A useful test should fail when the public behaviour regresses, not merely when a file disappears.
$ cd Demo-Greeting
$ prove -lv t
t/Demo-Greeting.t ..
ok
All tests successful.
Files=1, Tests=1, 0 wallclock secs
Result: PASS
Your test count and diagnostic lines will differ. The important result is a zero exit status and Result: PASS. If prove is unavailable, run the test file with perl -Ilib t/Demo-Greeting.t; that adds the local lib directory without installing anything.
Checkpoint
Run the tests after each meaningful code change. Fix warnings and failures at their source instead of hiding them with skipped tests.
5. Update release files
Record user-visible changes in Changes. Make the README describe the actual API, prerequisites, licence and test command. Check that the version in the module is suitable for a first release and that the generated MANIFEST includes every file needed to build and use it.
$ perl Makefile.PL
$ make test
$ make distcheck
"/usr/bin/perl" "-MExtUtils::Manifest=fullcheck" -e fullcheck
$ echo "$?"
0
A correct run finishes with exit status 0. If the manifest check reports a missing file, update the manifest or the distribution configuration, then rerun it. Do not create a tarball until the tests and distribution check pass.
6. Build the tarball only after review
When the working tree is ready, run the sequence recommended by perlnewmod:
$ perl Makefile.PL && make test && make distcheck && make dist
Created Demo-Greeting-0.01.tar.gz
The archive name and final wording vary with the module version and MakeMaker release. Verify that the tarball exists and inspect its contents without extracting over your source directory:
$ ls -lh Demo-Greeting-*.tar.gz
$ tar -tzf Demo-Greeting-*.tar.gz | sed -n '1,40p'
If you need to discard a locally generated archive, remove that specific tarball after checking its path. Do not use a broad recursive deletion in the parent directory. The source tree is your recovery copy.
7. Treat publication as a separate change
Uploading needs a PAUSE account. Request one at pause.perl.org and wait for approval, then follow the account instructions to upload the distribution. The alternative cpan-upload utility comes from the CPAN::Uploader distribution and is not the same as the local build commands.
Do not upload a tarball merely because it builds. Read the archive, review the licence and dependency declarations, and decide whether you can support bug reports. A public release is difficult to retract cleanly once other projects depend on it. If you find a bug after release, record the fix in Changes, add a regression test, rebuild and publish a new version through the normal PAUSE process.
Done means
- The package name was checked against existing CPAN modules before coding.
h2xscreated a pure-Perl skeleton with modern tests and no XS files.- The module uses strict and warnings, and its POD explains the public interface.
- Tests cover normal behaviour and the important failure paths.
make testandmake distcheckfinish successfully.- The README, Changes file and distribution manifest match the code.
- The tarball was reviewed before any separate decision to upload it to PAUSE.