67

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?

Machavity
  • 30,841
  • 27
  • 92
  • 100
Frew Schmidt
  • 9,364
  • 16
  • 64
  • 86

8 Answers8

110

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;
ikegami
  • 367,544
  • 15
  • 269
  • 518
ephemient
  • 198,619
  • 38
  • 280
  • 391
  • 3
    Usually you want to do an unshift so you're directory is at the front of the list. That way Perl doesn't have to search through all of @INC to find it. :) – brian d foy Oct 08 '08 at 22:17
  • Yeah, that's right, and so the BEGIN{push}=>`use lib` conversion isn't identical, either. But I wanted to show the minimum usable change from the question to make it work. Thanks for noticing :) – ephemient Oct 09 '08 at 00:34
  • There's also PERL5LIB and the -I switch, as Brian mentions. – Axeman Oct 10 '08 at 05:04
  • On windows I can call successfully using this method : use lib 'D:\webserver\sites\test\testing'; but not using, use lib '\testing'; (or use lib '..\testing'; or use lib '.\testing';). In both cases I am running script from test folder. How do I do relative naming. Is it difference in Linux and Windows. – msinfo Jan 25 '14 at 22:22
26

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.

brian d foy
  • 129,424
  • 31
  • 207
  • 592
15

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.

Berserk
  • 423
  • 2
  • 3
  • 3
    That pushing syntax looks uber-confusing. It's definitely pointing the wrong way. From a mechanical perspective. Is it the same as a comma? The comma is much more ambiguous about direction, and hence better... – Steven Lu May 31 '13 at 15:15
  • @StevenLu From [`perldoc perlop`](http://perldoc.perl.org/perlop.html#Comma-Operator): *"The `=>` operator is a synonym for the comma except that it causes a word on its left to be interpreted as a string if it begins with a letter or underscore and is composed only of letters, digits and underscores. [...] Otherwise, the `=>` operator behaves exactly as the comma operator or list argument separator, according to context."* `=>` is also known as the "fat comma." – ThisSuitIsBlackNot Jul 02 '14 at 20:42
  • Too bad the same does not hold for `<=`. – Steven Lu Jul 03 '14 at 11:30
8

'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.

Grzegorz Rożniecki
  • 27,415
  • 11
  • 90
  • 112
zigdon
  • 14,573
  • 6
  • 35
  • 54
3

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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1
    Usually you want to do an unshift so you're directory is at the front of the list. That way Perl doesn't have to search through all of @INC to find it. :) – brian d foy Oct 08 '08 at 22:16
  • Yeah, that too...I don't normally use relative names because I don't normally run scripts from a fixed directory, so... – Jonathan Leffler Oct 08 '08 at 22:38
2

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';
}
0

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

Billious
  • 101
  • 3
0

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.

Richard
  • 386
  • 4
  • 8