How do I "use" a Perl module in a directory not in @INC?

PerlModuleRelative Path

Perl 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, and
  • import-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.

see POD for lib::relative

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFrew SchmidtView Question on Stackoverflow
Solution 1 - PerlephemientView Answer on Stackoverflow
Solution 2 - Perlbrian d foyView Answer on Stackoverflow
Solution 3 - PerlBerserkView Answer on Stackoverflow
Solution 4 - PerlzigdonView Answer on Stackoverflow
Solution 5 - PerlJonathan LefflerView Answer on Stackoverflow
Solution 6 - PerlSimonView Answer on Stackoverflow
Solution 7 - PerlBilliousView Answer on Stackoverflow
Solution 8 - PerlRichardView Answer on Stackoverflow