perl.gg / essentials

Local Packages

2024-07-09

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:
use FindBin qw($RealBin);
$RealBin gives you the directory containing your script. Not where you ran it from, but where it actually lives on disk.
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)
The "Real" versions follow symlinks. If someone symlinked your script, $RealBin points to the actual location, not the symlink's directory.

Part 3: TELLING PERL WHERE TO LOOK

use lib ($RealBin, "$RealBin/lib");
The use lib pragma adds directories to @INC, which is Perl's module search path. Now Perl will look in:
1. The script's directory ($RealBin) 2. A lib subdirectory ($RealBin/lib) 3. All the standard system locations
Order matters here. Perl searches from left to right and stops at the first match, so your local modules will override the system ones.
.--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/

Part 4: YOUR FIRST LOCAL MODULE

Create MyUtils.pm in the same directory as your script:
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;
That trailing 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:
#!/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";
Output:
Hello, World! 5 squared is 25
The functions come in clean, and no package prefix is needed.

Part 6: THE EXPORTER DANCE

Exporter is Perl's mechanism for making functions available to importers. Let's break down what is happening:
use Exporter qw(import);
This imports Exporter's import() method into your package. That method handles the qw(...) list when someone uses your module.
our @EXPORT_OK = qw(greet square);
Functions listed here can be imported on request. The caller has to explicitly ask for them.

Compare to:

our @EXPORT = qw(greet);
Functions in @EXPORT are imported automatically. No request is needed.
ARRAY BEHAVIOR ----------- ---------------------------------------- @EXPORT Auto-imported (considered impolite) @EXPORT_OK Imported on request (the polite way) %EXPORT_TAGS Named groups of exports
The Perl community prefers @EXPORT_OK. Let the caller decide what they want in their namespace.

Part 7: ORGANIZING INTO SUBDIRECTORIES

As your project grows, you will want a lib directory:
my_project/ main.pl MyUtils.pm lib/ MathOps.pm StringOps.pm
Create lib/MathOps.pm:
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;
Your script can use both:
use MyUtils qw(greet); use MathOps qw(add multiply);

Part 8: THE COMPLETE EXAMPLE

Here is a full working setup. Three files:

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";
MyUtils.pm (same directory as main.pl):
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;
lib/MathOps.pm:
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:
package MyUtils; use Exporter qw(import); our @EXPORT_OK = qw(greet square cube); our %EXPORT_TAGS = ( all => \@EXPORT_OK );
Now callers can do:
use MyUtils qw(:all);
And they get greet, square, and cube without listing each one.

Part 10: NESTED PACKAGES

You can have hierarchical module names:
lib/ My/ Utils.pm Math/ Advanced.pm
lib/My/Utils.pm:
package My::Utils; # ... 1;
lib/My/Math/Advanced.pm:
package My::Math::Advanced; # ... 1;
Use them with:
use My::Utils qw(some_function); use My::Math::Advanced qw(factorial);
The :: in the package name maps to / in the filesystem.

Part 11: COMMON MISTAKES

Forgot the 1; at the end:
MyUtils.pm did not return a true value at main.pl line 5.
Fix: Add 1; as the last line of your module.

Wrong directory in use lib:

Can't locate MyUtils.pm in @INC...
Fix: Check that $RealBin points where you think. Add:
print "Looking in: $RealBin\n";
Package name does not match filename:
Undefined subroutine &MyUtilz::greet called...
Fix: The package statement must match the .pm filename exactly.

Part 12: WHY NOT JUST require?

You can skip Exporter entirely with require and explicit calls:
require "$RealBin/MyUtils.pm"; print MyUtils::greet("World");
But this has drawbacks:
* 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
For quick scripts, require works. For maintainable code, use Exporter.
.----------------. / \ | my_project/ | | +-----------+ | | | main.pl | | | +-----------+ | | | MyUtils.pm| | | +-----------+ | | | lib/ | | | | MathOps | | | +-----------+ | \ / '----------------'
perl.gg