DekGenius.com
[ Team LiB ] Previous Section Next Section

12.7 Setting the Path at the Right Time

The downside of use being executed at compile time is that it also looks at @INC at compile time, which can break your program in hard-to-understand ways unless you take @INC into consideration.

For example, suppose you have your own directory under /home/gilligan/lib, and you place your own Navigation::SeatOfPants module in /home/gilligan/lib/Navigation/SeatOfPants.pm. Simply saying:

use Navigation::SeatOfPants;

is unlikely to do anything useful because only the system directories (and typically the current directory) are considered for @INC. However, even adding:

push @INC, "/home/gilligan/lib";   # broken
use Navigation::SeatOfPants;

doesn't work. Why? Because the push happens at runtime, long after the use was attempted at compile time. One way to fix this is to add a BEGIN block around the push:

BEGIN { push @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 a simple pragma:

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 (think "unshift").[11] It does so because it is processed at compile time, not runtime. Hence, it's ready in time for the use immediately following.

[11] 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 encouraged to put it near the top of the file. This makes it easier to find and update when the file needs to move to a new system or when the lib directory's name changes. (Of course, you can eliminate use lib entirely if you can install your modules in a 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, you 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 the declaration of $LIB_DIR is established at compile time (so you won't get an error with use strict, although the actual use lib should complain), but the actual initialization to the /home/gilligan/lib/ path happens at runtime. Oops, too late again!

At this point, you 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 you 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 your needs.

    [ Team LiB ] Previous Section Next Section