Документация
HTML CSS PHP PERL другое

Section 3.9.  Setting the Path at the Right Time

 
Previous
Table of Contents
Next

3.9. Setting the Path at the Right Time

Perl finds modules by looking through the directories in the special Perl array, @INC. The use statement executes at compile time, so it looks at the module search path, @INC, at compile time. That can break our program in hard-to-understand ways unless we take @INC into consideration.

For example, suppose we have our own directory under /home/gilligan/lib, and we place our own Navigation::SeatOfPants module in /home/gilligan/lib/Navigation/SeatOfPants.pm. When we load our module, Perl won't find it.

use Navigation::SeatOfPants;

Perl complains to us that it can't find the module in @INC and shows us all of the directories it has in that array.

Can't locate Navigation/SeatofPants.pm in @INC (@INC contains: ...)

You might think that we should just add our module directory to @INC before we call the use. However, even adding:

unshift @INC, '/home/gilligan/lib';   # broken
use Navigation::SeatOfPants;

doesn't work. Why? Because the unshift happens at runtime, long after the use was attempted at compile time. The two statements are lexically adjacent but not temporally adjacent. Just because we wrote them next to each other doesn't mean they execute in that order. We want to change @INC before the use executes. One way to fix this is to add a BEGIN block around the push:

BEGIN { unshift @INC, '/home/gilligan/lib'; }
use Navigation::SeatOfPants;

Now the BEGIN block compiles and executes at compile time, setting up the proper path for the following use.

However, this is noisy and prone to require far more explanation than you might be comfortable with, especially for the maintenance programmer who has to edit your code later. Let's replace all that clutter with that simple pragma we used before:

use lib '/home/gilligan/lib';
use Navigation::SeatOfPants;

Here, the lib pragma takes one or more arguments and adds them at the beginning of the @INC array, just like unshift did before.[*] It works because it executes at compile time, not runtime. Hence, it's ready in time for the use immediately following.

[*] use lib also unshifts an architecture-dependent library below the requested library, making it more valuable than the explicit counterpart presented earlier.

Because a use lib pragma will pretty much always have a site-dependent pathname, it is traditional and we encourage you to put it near the top of the file. This makes it easier to find and update when we need to move the file to a new system or when the lib directory's name changes. (Of course, we can eliminate use lib entirely if we can install our modules in standard @INC locations, but that's not always practical.)

Think of use lib as not "use this library" but rather "use this path to find my libraries (and modules)." Too often, we see code written like:

use lib '/home/gilligan/lib/Navigation/SeatOfPants.pm'; # WRONG

and then the programmer wonders why it didn't pull in the definitions. Be aware that use lib indeed runs at compile time, so this also doesn't work:

my $LIB_DIR = '/home/gilligan/lib';
...
use lib $LIB_DIR;     # BROKEN
use Navigation::SeatOfPants;

Certainly, Perl establishes the declaration of the $LIB_DIR variable at compile time (so we won't get an error with use strict, although the actual use lib should complain), but the actual assignment of the /home/gilligan/lib/ value doesn't happen until runtime. Oops, too late again!

At this point, we need to put something inside a BEGIN block or perhaps rely on yet another compile-time operation: setting a constant with use constant:

use constant LIB_DIR => '/home/gilligan/lib';
...
use lib LIB_DIR;
use Navigation::SeatOfPants;

There. Fixed again. That is, until we need the library to depend on the result of a calculation. (Where will it all end? Somebody stop the madness!) This should handle about 99 percent of our needs.

3.9.1. Handling Module Dependencies

We just saw that if we try to install a module that uses Module::Build, we have to install Module::Build first. That's a mild case of the general dependency headache, and all the coconuts on our castaways' island aren't going to fix it. We might have to install several other modules too, each of which, in turn, depends on even more modules.

Fortunately, we have tools to help us. The CPAN.pm module has been part of the core distribution since Perl 5.004. It gives us an interactive module installation shell.

$ perl -MCPAN -e shell
cpan shell -- CPAN exploration and modules installation (v1.7601)
ReadLine support available (try 'install Bundle::CPAN')

cpan>

To install a module along with its dependencies, we issue the install command with the name of the module. Now, CPAN.pm handles all the work of downloading, unpacking, building, testing, and installing the module, and it does so recursively for all its dependencies.

cpan> install CGI::Prototype

That's a bit too much work, though, so brian created the cpan script, which also comes with Perl. We simply list the modules we want to install, and it handles it for us.

$ cpan CGI::Prototype HTTP::Cookies::Safari Test::Pod

Another tool, CPANPLUS, is a complete rewrite of CPAN.pm, but it isn't part of the core distribution as we write this.

$ perl -MCPANPLUS -e shell
CPANPLUS::Shell::Default -- CPAN exploration and modules installation (v0.03)
*** Please report bugs to <cpanplus-bugs@lists.sourceforge.net>.
*** Using CPANPLUS::Backend v0.049.
*** ReadLine support available (try 'i Term::ReadLine::Perl').

CPAN Terminal>

To install a module, we use the i command.

CPAN Terminal> i CGI::Prototype

The CPANPLUS module also comes with a convenience script, called cpanp. If we give it the i switch and a list of modules, it installs them just like before.

$ cpanp i CGI::Prototype HTTP::Cookies::Safari Test::Pod


Previous
Table of Contents
Next
© 2000- NIV