Local Packages
This page shows how to organize your Perl code into reusable pieces that live next to your script, without touching the system or CPAN. Local packages give you a clean way to share functions across files on your own machine. You just drop the module files beside your script and Perl finds them.Part 1: THE PROBLEM
You start with a single script and it slowly grows. Functions multiply, files copy each other, and the project becomes hard to track. Breaking it into modules is the right move, but installing them system-wide feels like overkill for a personal project. Local packages solve that by letting your modules live right next to your script. They stay portable and simple.Part 2: FINDING YOURSELF
First, you need to know where your script actually lives on the filesystem:$RealBin gives you the directory containing your script. Not where you ran it from, but where it actually lives on disk.use FindBin qw($RealBin);
The "Real" versions follow symlinks. If someone symlinked your script, $RealBin points to the actual location, not the symlink's directory.VARIABLE WHAT IT GIVES YOU ---------- ---------------------------------------- $RealBin Directory containing the script $RealScript Name of the script itself $Bin Same as $RealBin (legacy name) $Script Same as $RealScript (legacy name)
Part 3: TELLING PERL WHERE TO LOOK
The use lib pragma adds directories to @INC, which is Perl's module search path. Now Perl will look in:use lib ($RealBin, "$RealBin/lib");
Order matters here. Perl searches from left to right and stops at the first match, so your local modules will override the system ones.1. The script's directory ($RealBin) 2. A lib subdirectory ($RealBin/lib) 3. All the standard system locations
.--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/
Part 4: YOUR FIRST LOCAL MODULE
Create MyUtils.pm in the same directory as your script:That trailingpackage MyUtils; use strict; use warnings; use Exporter qw(import); our @EXPORT_OK = qw(greet square); sub greet { my ($name) = @_; return "Hello, $name!"; } sub square { my ($n) = @_; return $n * $n; } 1;
1; is required. It tells Perl that the module loaded successfully. Without it, your script dies with a cryptic error.
Part 5: USING YOUR MODULE
Now your main script can use it:Output:#!/usr/bin/env perl use strict; use warnings; use FindBin qw($RealBin); use lib ($RealBin, "$RealBin/lib"); use MyUtils qw(greet square); print greet("World"), "\n"; print "5 squared is ", square(5), "\n";
The functions come in clean, and no package prefix is needed.Hello, World! 5 squared is 25
Part 6: THE EXPORTER DANCE
Exporter is Perl's mechanism for making functions available to importers. Let's break down what is happening:This imports Exporter'suse Exporter qw(import);
import() method into your package. That method handles the qw(...) list when someone uses your module.
Functions listed here can be imported on request. The caller has to explicitly ask for them.our @EXPORT_OK = qw(greet square);
Compare to:
Functions inour @EXPORT = qw(greet);
@EXPORT are imported automatically. No request is needed.
The Perl community prefers @EXPORT_OK. Let the caller decide what they want in their namespace.ARRAY BEHAVIOR ----------- ---------------------------------------- @EXPORT Auto-imported (considered impolite) @EXPORT_OK Imported on request (the polite way) %EXPORT_TAGS Named groups of exports
Part 7: ORGANIZING INTO SUBDIRECTORIES
As your project grows, you will want a lib directory:Create lib/MathOps.pm:my_project/ main.pl MyUtils.pm lib/ MathOps.pm StringOps.pm
Your script can use both:package MathOps; use strict; use warnings; use Exporter qw(import); our @EXPORT_OK = qw(add subtract multiply divide); sub add { $_[0] + $_[1] } sub subtract { $_[0] - $_[1] } sub multiply { $_[0] * $_[1] } sub divide { my ($a, $b) = @_; die "Division by zero" if $b == 0; return $a / $b; } 1;
use MyUtils qw(greet); use MathOps qw(add multiply);
Part 8: THE COMPLETE EXAMPLE
Here is a full working setup. Three files:main.pl:
MyUtils.pm (same directory as main.pl):#!/usr/bin/env perl use strict; use warnings; use FindBin qw($RealBin); use lib ($RealBin, "$RealBin/lib"); use MyUtils qw(greet square); use MathOps qw(add multiply); # Use the imported functions print greet("Perl Hacker"), "\n"; print "3 squared: ", square(3), "\n"; print "5 + 7 = ", add(5, 7), "\n"; print "4 * 8 = ", multiply(4, 8), "\n";
lib/MathOps.pm:package MyUtils; use strict; use warnings; use Exporter qw(import); our @EXPORT_OK = qw(greet square); sub greet { my ($name) = @_; return "Hello, $name!"; } sub square { my ($n) = @_; return $n * $n; } 1;
package MathOps; use strict; use warnings; use Exporter qw(import); our @EXPORT_OK = qw(add subtract multiply divide); sub add { $_[0] + $_[1] } sub subtract { $_[0] - $_[1] } sub multiply { $_[0] * $_[1] } sub divide { my ($a, $b) = @_; die "Division by zero" if $b == 0; return $a / $b; } 1;
Part 9: IMPORTING EVERYTHING
Sometimes you want all exports. Use the:all tag:
Now callers can do:package MyUtils; use Exporter qw(import); our @EXPORT_OK = qw(greet square cube); our %EXPORT_TAGS = ( all => \@EXPORT_OK );
And they get greet, square, and cube without listing each one.use MyUtils qw(:all);
Part 10: NESTED PACKAGES
You can have hierarchical module names:lib/My/Utils.pm:lib/ My/ Utils.pm Math/ Advanced.pm
lib/My/Math/Advanced.pm:package My::Utils; # ... 1;
Use them with:package My::Math::Advanced; # ... 1;
Theuse My::Utils qw(some_function); use My::Math::Advanced qw(factorial);
:: in the package name maps to / in the filesystem.
Part 11: COMMON MISTAKES
Forgot the1; at the end:
Fix: AddMyUtils.pm did not return a true value at main.pl line 5.
1; as the last line of your module.
Wrong directory in use lib:
Fix: Check that $RealBin points where you think. Add:Can't locate MyUtils.pm in @INC...
Package name does not match filename:print "Looking in: $RealBin\n";
Fix: The package statement must match theUndefined subroutine &MyUtilz::greet called...
.pm filename exactly.
Part 12: WHY NOT JUST require?
You can skip Exporter entirely with require and explicit calls:But this has drawbacks:require "$RealBin/MyUtils.pm"; print MyUtils::greet("World");
For quick scripts, require works. For maintainable code, use Exporter.* No import list - you always use full package names * Runs at runtime, not compile time - errors caught later * Less idiomatic - other Perl programmers expect use
perl.gg.----------------. / \ | my_project/ | | +-----------+ | | | main.pl | | | +-----------+ | | | MyUtils.pm| | | +-----------+ | | | lib/ | | | | MathOps | | | +-----------+ | \ / '----------------'