How do I "use" a Perl module in a directory not in @INC?
PerlModuleRelative PathPerl Problem Overview
I have a module in the parent directory of my script and I would like to 'use' it.
If I do
use '../Foo.pm';
I get syntax errors.
I tried to do:
push @INC, '..';
use EPMS;
and .. apparently doesn't show up in @INC
I'm going crazy! What's wrong here?
Perl Solutions
Solution 1 - Perl
use
takes place at compile-time, so this would work:
BEGIN {push @INC, '..'}
use EPMS;
But the better solution is to use lib
, which is a nicer way of writing the above:
use lib '..';
use EPMS;
In case you are running from a different directory, though, the use of FindBin
is recommended:
use FindBin; # locate this script
use lib "$FindBin::RealBin/.."; # use the parent directory
use EPMS;
Solution 2 - Perl
There are several ways you can modify @INC
.
-
set
PERL5LIB
, as documented in perlrun -
use the
-I
switch on the command line, also documented in perlrun. You can also apply this automatically with PERL5OPT, but just use PERL5LIB if you are going to do that. -
use lib
inside your program, although this is fragile since another person on a different machine might have it in a different directory. -
Manually modify
@INC
, making sure you do that at compile time if you want to pull in a module with use. That's too much work though. -
require
the filename directly. While this is possible, it doesn't allow that filename to load files in the same directory. This would definitely raise eyebrows in a code review.
Solution 3 - Perl
Personally I prefer to keep my modules (those that I write for myself or for systems I can control) in a certain directory, and also to place them in a subdirectory. As in:
/www/modules/MyMods/Foo.pm
/www/modules/MyMods/Bar.pm
And then where I use them:
use lib qw(/www/modules);
use MyMods::Foo;
use MyMods::Bar;
As an aside.. when it comes to pushing, I prefer the fat-arrow comma:
push @array => $pushee;
But that's just a matter of preference.
Solution 4 - Perl
'use lib' is the answer, as @ephemient mentioned earlier. One other option is to use require/import instead of use. It means the module wouldn't be loaded at compile time, but instead in runtime.
That will allow you to modify @INC as you tried there, or you could pass require a path to the file instead of the module name. From 'perldoc -f require':
> If EXPR is a bareword, the require assumes a ".pm" extension and > replaces "::" with "/" in the filename for you, to make it easy to > load standard modules. This form of loading of modules does not risk > altering your namespace.
Solution 5 - Perl
You have to have the push
processed before the use
is -- and use
is processed early. So, you'll need a BEGIN { push @INC, ".."; }
to have a chance, I believe.
Solution 6 - Perl
As reported by "perldoc -f use":
> It is exactly equivalent to
> BEGIN { require Module; import Module LIST; }
> except that Module must be a bareword.
Putting that another way, "use" is equivalent to:
- running at compile time,
- converting the package name to a file name,
require
-ing that file name, andimport
-ing that package.
So, instead of calling use, you can call require and import inside a BEGIN block:
BEGIN {
require '../EPMS.pm';
EPMS->import();
}
And of course, if your module don't actually do any symbol exporting or other initialization when you call import, you can leave that line out:
BEGIN {
require '../EPMS.pm';
}
Solution 7 - Perl
Some IDEs don't work correctly with 'use lib', the favored answer. I found 'use lib::relative' works with my IDE, JetBrains' WebStorm.
Solution 8 - Perl
The reason it's not working is because what you're adding to @INC
is relative to the current working directory in the command line rather than the script's directory.
For example, if you're currently in:
a/b/
And the script you're running has this URL:
a/b/modules/tests/test1.pl
BEGIN {
unshift(@INC, "..");
}
The above will mean that ..
results in directory a/
rather than a/b/modules
.
Either you must change ..
to ./modules
in your code or do a cd modules/tests
in the command line before running the script again.