For Perl Programmers : only
by Brian IngersonMarch 18, 2003
Have you ever wished that you could have more than one version of a Perl module installed on your system, and that you could easily tell Perl exactly which one you wanted to load? Perhaps you have some legacy programs that only run with older versions of certain modules, while the rest of your system is coded to the more-modern versions of the same module. Or maybe you administer a multiuser system, where your various users request different module versions.
Perl's built-in mechanism for module version control is very rudimentary. Basically, you can say:
use XML::Parser 2.27;
The use command will load XML::Parser and then proceed to die unless
$XML::Parser::VERSION is greater than or equal to 2.27. There is no
way to ask for one specific version or a range of versions. Most of the
time this is OK. It's OK if you assume that successive versions of
modules always improve, never drop functionality and are fully backward
compatible. Unfortunately, in real life, this isn't always true.
Take Lincoln Stein's excellent GD module for example. GD.pm is a
toolset for creating graphic images from Perl programs. Up to version
1.19, GD supported the GIF format. Due to GIF's licensing
restrictions, the author was forced to retract support. GIF support was
replaced by the PNG format, and later JPEG support was added. If you
are required to use GD for both GIF and PNG format types, then you need to
do some monkeying around with library paths to get it to work.
With big projects in restrictive environments, dealing with module versioning issues can quickly become a tangled briar patch. When your needs for using specific modules become too thorny, you need a sharper chainsaw. This article describes such a saw.
The Only Way
Introducing only.pm! only is a full featured system for installing
and loading multiple versions of Perl modules.
To make sure that your program loads version 1.19 of GD, simply say:
use only GD => 1.19;
If you know that any of the GD versions from 2.01 up to 2.06 are OK, then
say:
use only GD => '2.01-2.06';
If you also want to import GD::foo and GD::bar, then:
use only GD => '2.01-2.06', qw(foo bar);
only acts as an extension to Perl's use command. It intercepts the
parameters that you would normally pass to use along with an
acceptable version range. It takes all of that information and does a
"heap of bit-wrangling" to make sure that you get the version of the
module you wanted. In every other respect, it tries to act like a regular
use statement.
Easy Installations
How do you go about installing several versions of Perl modules? Perl is
really only designed to support the installation of a single module
version. Whenever you install a new version of a module, it simply
overwrites the older version. This is known as upgrading. Usually that's
what you want, but in the context of only, you actually want to have
multiple versions installed simultaneously.
Advanced Perl programmers know that is possible to install modules into
different directories. You can supply a PREFIX= parameter to the make
install process. But then you have to remember where you installed the
module, and manually adjust @INC to have the right sequence of paths.
That's just no fun.
Fortunately, only makes it extremely simple to install multiple
versions. To start with, just go about building your module in the
usual way:
tar xvzf Cat-Fancy-0.09.tar.gz
cd Cat-Fancy-0.09
perl Makefile.PL
make test
Normally, the next step is make install. But if you want to store version
0.09 separate from any other version of Cat::Fancy, do this:
perl -Monly=install
This actually does the same procedure as make install would except
that it automatically determines a safe place to stick your module; one
that only.pm can find when you say:
use only Cat::Fancy => 0.09;
Note: If you need authorized access to install modules on your system, then you can do:
sudo perl -Monly=install
But be careful. The perl used by sudo may not be the same perl
as the one used by make. If this is the case, then you'll need to
specify the full path to perl.
Where Is My Only Module?
You may wonder, "Where exactly do these modules get installed and will they conflict with my existing modules?". The short answer is, "They get installed exactly where you told them to!".
When you install the only module, you are asked to select a base
directory where only::install can install modules. The default value
is a modification of your Perl's sitelib directory. For instance, if
your sitelib was:
/usr/local/perl580/lib/sitelib/5.8.0
then only.pm would default to:
/usr/local/perl580/lib/version/5.8.0
Even though this is the default, you are prompted to select any
directory you want. Your choice is saved permanently in only::config.
The constant only::config::versionlib, becomes the base directory
where only will install and search for versioned modules.
If you really need to, then you can override this directory as well. For installation, you would say:
perl -Monly=install - versionlib=/home/ingy/modules
The versionlib is just the base directory. only separates various module
versions by sticking them into a subdirectory named after the version. So
Cat::Fancy would be installed as:
/usr/local/perl580/lib/version/5.8.0/0.09/Cat/Fancy.pm
Module::Build
Many new Perl modules are using Module::Build for their build process,
instead of the age-old Makefile.PL and ExtUtils::MakeMaker.
Module::Build is a wonderfully organized and extensible replacement
for its stalwart yet terribly crufty predecessor.
One of the side benefits of modules distributions that have
Module::Build is that you can do version-specific installations
natively by saying:
perl Build.PL
./Build versioninstall
Although this is just a pass-through call to only::install, it does
not suffer from the aforementioned "sudo" problem.
only The::Facts
Back to only.pm. In this section, I'll discuss all the gory details of
the use only syntax. It really isn't that bad. The basic form is:
use only MODULE => CONDITION;
where MODULE is a module name, and CONDITION is either a simple version number or a more complex version specification. More on version conditions in a moment. If you have arguments to pass to the module, then simply tack them on to the end:
use only MODULE => CONDITION, ARGUMENTS;
only even accounts for situations where different versions need different
arguments. You match up the conditions and arguments as a set of anonymous
arrays:
use only MODULE =>
[ CONDITION1, ARGUMENTS1 ],
...,
[ CONDITION7, ARGUMENTS7 ];
Finally, there are some special options that you can pass to only to tell it
how to behave. This is accomplished syntactically by passing an anonymous hash
of option/value pairs. Put the options hash directly after use only:
use only { OPTION => VALUE},
MODULE => CONDITION;
If you want to set the options globally (for all subsequent only
interaction), then just specify the options without any other arguments. For
example, to override the versionlib option for all use only ...
statements, say:
use only { versionlib => '/home/ingy/modules' };
Hazardous Conditions
Even though a "version condition" can be as simple as a single version
number like '0.42', only offers flexible syntax for expressing
exactly which versions you are (and aren't) interested in.
If you want to specify a list of versions, then just use a space-separated enumeration:
use only Bird::Talk => '0.42 0.44 0.47 0.50';
If your version requirements fall into a range, then you can specify those, too. Just use two versions, separated by a dash:
use only Bird::Talk => '0.42-0.50';
Of course, you can list multiple ranges as well. And if you leave one of the versions off the range, then that means the range is open-ended.
use only Bird::Talk => '0.42-0.50 0.55-0.62 0.67-';
Sometimes it's easier to just specify the versions you don't want. Using
a '!' in front of either a range or a single version, negates that
meaning. To avoid all versions of Bird::Talk below 0.42, and also the
extremely buggy version .53, say:
use only Bird::Talk => '!-0.41 !0.53';
When more than one eligible version of Bird::Talk is installed on your
system, only always chooses the highest version. If you don't specify any
version, then that is an indication to choose the highest-numbered version.
This is different than saying:
use Bird::Talk;
because only will search your versionlib first.
Pages: 1, 2 |





