Perl Cookbook

Perl CookbookSearch this book
Previous: 12.6. Automating Module Clean-UpChapter 12
Packages, Libraries, and Modules
Next: 12.8. Preparing a Module for Distribution
 

12.7. Keeping Your Own Module Directory

Problem

You don't want to install your own personal modules in the standard per-system extension library.

Solution

You have several choices: use Perl's -I command line switch; set your PERL5LIB environment variable; or employ the use lib pragma, possibly in conjunction with the FindBin module.

Discussion

The @INC array contains a list of directories that are consulted every time a do, require, or use compiles code from another file, library, or module. You can print these out easily from the command line:

% perl -e 'for (@INC) { printf "%d %s\n", $i++, $_ }'
0 /usr/local/perl/lib/i686-linux/5.004
1 /usr/local/perl/lib
2 /usr/local/perl/lib/site_perl/i686-linux
3 /usr/local/perl/lib/site_perl
4 .

The first two directories, elements 0 and 1 of @INC, are the standard architecture-dependent and architecture-independent directories, which all standard libraries, modules, and pragmas will go into. You have two of them because some modules contain information or formatting that makes sense only on that particular architecture. For example, the Config module contains information that cannot be shared across several architectures, so it goes in the 0th array element. Modules that include compiled C components, such as Socket.so, are also placed there. Most modules, however, go in the platform-independent directory in the 1st element.

The next pair, elements 2 and 3 above, fulfills roles analogous to elements 0 and 1, but on a site-specific basis. Suppose you have a module that didn't come with Perl, like a module from CPAN or one you wrote yourself. When you or (more likely) your system administrator installs this module, its components go into one of the site-specific directories. You are encouraged to use these for any modules that your entire site should be able to access conveniently.

The last standard component, "." (your current working directory), is useful only when developing and testing your software, not when deploying it. If your modules are in the same directory that you last chdired to, you're fine. If you're anywhere else, it doesn't work.

So sometimes none of the @INC directories work out. Maybe you have your own personal modules. Perhaps your project group has particular modules that are relevant only to that project. In these cases, you need to augment the standard @INC search.

The first approach involves using a command-line flag, -Idirlist. The dirlist is a colon-separated[1] list of one or more directories, which will be prepended to the front of the @INC array. This works well for simple command lines, and thus can be used on a per-command basis, such as when you call a quick one-liner from a shell script.

[1] Comma-separated on MacOS.

This technique should not be included in the #! (pound-bang) line. First, it's not much fun to modify each program. More importantly, some older operating systems have bugs related to how long that line can be, typically 32 characters, including the #! part. That means if you have a very long path, such as #!/opt/languages/free/extrabits/perl, you may get the mysterious "Command not found" error. Perl does its best to rescan the line manually, but it's still too dicey to rely on.

Often, a better solution is to set the PERL5LIB environment variable. This can be done in your shell start-up file. Or, your system administrator may want to do so in a systemwide start-up file so all users can benefit. For example, suppose you have all your own modules in a directory called ~/perllib. You would place one of the following lines in your shell start-up file, depending on which shell you use:

# syntax for sh, bash, ksh, or zsh
$ export PERL5LIB=$HOME/perllib

# syntax for csh or tcsh
% setenv PERL5LIB ~/perllib

Probably the most convenient solution from your users' perspective is for you to add a use lib pragma near the top of your script. That way the users of the program don't need to take any special action to run your program. Imagine a hypothetical project called Spectre whose programs rely on its own set of libraries. Those programs could have a statement like this at their start:

use lib "/projects/spectre/lib";

What happens when you don't know the exact path to the library? Perhaps you've allowed the whole project to be installed in an arbitrary path. You could create an elaborate installation procedure to dynamically update the script, but even if you did, paths would still be frozen at installation time. If someone moved the files later, the libraries wouldn't be found.

The FindBin module conveniently solves this problem. This module tries to compute the full path to the executing script's enclosing directory, setting an importable package variable called $Bin to that directory. Typical usage is either to look for modules in the same directory as the program or in a lib directory at the same level.

To demonstrate the first case, suppose you have a program called /wherever/spectre/myprog that needs to look in /wherever/spectre for its modules, but you don't want to hardcode that path.

use FindBin;
use lib $FindBin::Bin;

The second case would be used if your program lives in /wherever/spectre/bin/myprog but needs to look at /wherever/spectre/lib for its modules.

use FindBin qw($Bin);
use lib "$Bin/../lib";

See Also

The documentation for the standard use lib pragma and the standard FindBin module; the discussion of the PERL5LIB environment in perl (1); your shell's syntax for setting environment variables


Previous: 12.6. Automating Module Clean-UpPerl CookbookNext: 12.8. Preparing a Module for Distribution
12.6. Automating Module Clean-UpBook Index12.8. Preparing a Module for Distribution