• Helmut Weber
  • 08.09.2011

CPAN-Modul erstellen und veröffentlichen


Perl ist eine freie, plattformunabhängige und interpretierte Programmiersprache. Als Stärken dieser Programmiersprache gelten die Bearbeitung von Texten mit Hilfe regulärer Ausdrücke sowie die Verfügbarkeit von vielen freien Modulen, die über CPAN an einem zentralen Ort gesammelt sind.

Wenn in einem Programm die gleichen Zeilen mehrfach auftreten ist es Sinnvoll, diese in eine Funktion auszulagern. Wird eine solche Funktion in mehreren Programmen verwendet, sollte diese in ein Modul ausgelagert werden um an einer zentralen Stelle gepflegt werden zu können. Wie ein solches Modul erstellt und über CPAN veröffentlicht wird, möchte ich in diesem Blog-Beitrag zeigen.

Vorbereitung

Damit ein Perl-Modul über CPAN veröffentlicht werden kann, muss dieses Modul bestimmte Voraussetzung erfüllen. Dadurch wird der Aufbau der Module vereinheitlicht und eine Mindestanforderung an Qualität (Abhängigkeiten, Tests, Dokumentation) eingehalten. In Perl gibt es das CPAN-Modul Module::Starter, welches dem Programmierer die Einhaltung dieser Voraussetzungen erleichtert. Unter Debian kann dieses Modul einfach über die Paketverwaltung installiert werden:

aptitude install libmodule-starter-perl

Alternativ kann das Modul auch direkt mit dem cpan-Befehl installiert werden:

cpan -i Module::Starter

Grundgerüst für ein neues CPAN-Modul erstellen

Zuerst legen wir uns ein Verzeichnis an, in dem wir unser Modul erstellen möchten:

mkdir /home/username/CPAN
cd /home/username/CPAN

Danach kann das einheitliche Grundgerüst eines CPAN-Moduls mittels Module::Starter erzeugt werden:

module-starter -mb --module=Mein::Modul --author="Max Mustermann" --email=max.mustermann@example.org

Die Parameter module, author und email sind Pflichtangaben. Der Parameter mb bewirkt, dass Module::Starter anstatt standardmäßig ExtUtils::MakeMaker das Modul Module::Build verwendet. Weitere Parameter können aus der Dokumentation des Moduls Module::Starter entnommen werden.

Durch die letzte Anweisung wurde folgende Struktur angelegt, die mit dem Kommandozeilen-Befehl tree grafisch ausgegeben werden kann:

Mein-Modul
├── Build.PL
├── Changes
├── ignore.txt
├── lib
│   └── Mein
│       └── Modul.pm
├── MANIFEST
├── README
└── t
    ├── 00-load.t
    ├── boilerplate.t
    ├── manifest.t
    ├── pod-coverage.t
    └── pod.t

In der Datei Build.PL werden Parameter für das kompilieren des Moduls eingetragen. Unter anderem werden dort die Abhängigkeiten zu anderen Modulen (falls vorhanden) ergänzt:

use strict;
use warnings;
use Module::Build;

my $builder = Module::Build->new(
    module_name         => 'Mein::Modul',
    license             => 'perl',
    dist_author         => q{Max Mustermann },
    dist_version_from   => 'lib/Mein/Modul.pm',
    build_requires => {
        'Test::More' => 0,
    },
    requires => {
        'Anderes::Modul' => 4.00,
        'Noch::Ein::Anderes::Modul' => 0,
    },
    add_to_cleanup      => [ 'Mein-Modul-*' ],
    create_makefile_pl => 'traditional',    create_readme => 1,
    meta_merge => {
        resources => {
            repository => 'https://github.com/bitbetrieb/CGI-Session-ID-crypt_openssl'
        }
    },
);

$builder->create_build_script();

In der Datei Changes werden alle Veränderungen am Modul festgehalten. Diese Datei sollte gut gepflegt werden, damit Veränderungen nachvollzogen werden können.

Revision history for Mein-Modul

1.00    08. September 2011
        First version created by Module::Starter

Die Datei ignore.txt kann gelöscht werden. Diese wird nur benötigt, wenn zum kompilieren das Modul ExtUtils::MakeMaker verwendet wird.

Für das Modul selbst wurde ein Grundgerüst unter Mein-Modul/lib/Mein/Modul.pm erstellt. Dieses Grundgerüst dient als Vorlage für das Modul selbst und kann nun für die eigenen Funktionen angepasst werden. Will man Konflikte mit einer gleichnamigen Variable $VERSION im Programm vermeiden, sollte die Variable $VERSION um den Paketnamen ergänzt werden:

$Mein::Modul::VERSION = '1.00';

In der Datei MANIFEST werden alle Dateien aufgelistet, die für das Modul notwendig sind. Alle anderen Dateien in dem Modul-Verzeichnis werden beim Kompilieren des Moduls ignoriert. Diese Datei sollte immer aktuell gehalten werden, und kann während dem Kompilieren geprüft sowie bei Bedarf angepasst werden. Dazu später jedoch mehr.

Neben der Datei MANIFEST ist es hilfreich, eine Datei MANIFEST.SKIP anzulegen, in der Dateien enthalten sind die auf jeden Fall ignoriert werden können (z.B. Dateien für die Versionsverwaltung oder ähnliches).

# Dateien für die Versionsverwaltung ignorieren
\bRCS\b
\bCVS\b
,v$
\B\.svn\b

# Dateien die durch Makemaker erzeugt wurden ignorieren
\bMakefile$
\bblib
\bMakeMaker-\d
\bpm_to_blib$
\bblibdirs$
^MANIFEST\.SKIP$

# Dateien die durch Module::Build erzeugt wurden ignorieren
\bBuild$
\b_build
\bcover_db

# Temporäre- und Backup-Dateien ignorieren
~$
\.tmp$
\.old$
\.bak$
\#$
\b\.#
\.cvsignore
\.svnignore
\ignore.txt

Es wurde eine README-Datei angelegt, in der bereits der Grundaufbau der Dokumentation für das Modul enthalten ist. Diese Datei kann nach Belieben ergänzt werden.

Im Ordner t werden Test-Skripte abgelegt, Welche die Funktionalität des Moduls beim Installieren prüfen. Durch das Anlegen des Moduls mit Module::Starter wurden bereits einfache Testfunktionen integriert. Je komplexer das Modul aufgebaut wird, desto umfangreicher sollten auch die dazugehörigen Test-Skripte sein.

Generieren des Moduls

Das Generieren des Moduls geschieht in mehreren Schritten und beginnt mit folgender Anweisung:

perl Build.PL

Aktualisieren der MANIFEST-Datei:

./Build manifest

Feststellen, ob Dateien im Verzeichnis enthalten sind, jedoch nicht in der MANIFEST-Datei und anders herum:

./Build distcheck

Testen, ob der Build-Prozess funktionieren würde:

./Build disttest

Wenn alle Befehle erfolgreich abgeschlossen wurden, kann nun mittels folgendem Befehl eine .tar.gz-Datei des Moduls erzeugt werden:

./Build dist

Modul in CPAN veröffentlichen

Nun wurde eine Datei Mein-Modul-1.00.tar.gz erstellt, die per PAUSE in CPAN übertragen werden kann. Nach dem Anmelden bei PAUSE kann dort über die Funktion Upload a file to CPAN das gerade Erstellte Modul hochgeladen werden. Nach kurzer Zeit sollte dieses Modul dann über CPAN für jeden Perl-Programmierer verfügbar sein. Herzlichen Glückwunsch!

Schlussbemerkung

Diese Dokumentation habe ich während der Erstellung meines ersten CPAN-Moduls CGI::Session::ID::crypt_openssl erstellt. Dieses Modul musste ich Erstellen, da das Modul CGI::Session für die Erzeugung der Sitzungs-ID keine ausreichend generierte Zufallszahl implementiert hat. Nach Kontaktaufnahme mit dem Betreuer des Moduls Mark Stosberg hat er mich dazu ermutigt, hierfür ein eigenes Modul zu erstellen, und dies unter CPAN zu veröffentlichen. Für diesen Anstoß möchte ich mich bei Mark recht herzlich bedanken.

Weiterführende Links

Für das Erstellen eines CPAN-Moduls sowie für die Erzeugung dieser Dokumentation, haben mir folgenden Seiten maßgeblich geholfen:

http://www.rainboxx.de/2008/10/schreib-deinen-code-als-wurde.html
http://cpansearch.perl.org/src/XSAWYERX/Module-Starter-1.58/getting-started.html
http://wiki.perl-community.de/foswiki/bin/view/Wissensbasis/WieErstelleIchEinModul
http://bratislava.pm.org/en/tutorial/new-module.html
https://sites.google.com/site/arjunwebworld/Home/programming/create-cpan-module