How do I use a Perl module from a relative location?

Viewed 39669

I have a dir called foo, and in that I have lib and bin. The scripts in bin need stuff in lib. I do something like this:

#!perl
use strict;
use warnings;
use lib '../lib';
use Foo; # <-- comes from lib

But that means I have to be in the bin dir to run the script. Surely there is a better way. What's the Right Way to do this?

8 Answers

The standard FindBin module does what you want.

use FindBin;
use lib "$FindBin::Bin/../lib";

perldoc FindBin for more.

Parse out the complete path to your .pl via __FILE__ and and tack the ../lib on the end or pop off the last element of split(/\//,__FILE__) and add /lib to that.

I generally use this technique. Its sadly inspired from my PHP days:

Its handy in situations where you know where a given file will be relative to the current one, and aren't sure of the entry points it may be called in or the surrounding environment at calltime.

However, I would generally use this technique only for test scripts which need dummy libraries for emulating things.

use File::Basename ();
use Cwd            ();
my $base_dir;
my $relative_path; 
BEGIN {
    $relative_path = '../../' # Path to base of project relative to the current file
    $base_dir = Cwd::realpath( File::Basename::dirname(__FILE__) .'/' . $relative_path );
}


use lib "${base_dir}/lib";
use Foo;

Ideally there should be some module somewhere that does this, if not, I'm half tempted to write one:

use Some::Module ();
use lib Some::Module::relative_self('../../lib', __FILE__ ); 

The "FindBin" module will only work if the directory that the perl script resides in is in your system PATH, else it will fail. To overcome that you can manipulate the $0 value to get your path-to-perl-module information and pass the value to use lib.

Something like this -

BEGIN {
    use File::Spec::Functions qw(rel2abs);
    use File::Basename qw(dirname);

    #Covert the script path to absolute and get its directory name
    our $path = dirname( rel2abs($0) );

    #Replace the bin tag with lib to get module directory
    $path =~ s{bin/?$}{lib};
}

use lib $path;

EDIT: The FindBin module works just perfectly and can be used as described in Michael's answer. My understanding of its workings was incomplete and so led me to making the first comment which I now retract. Anyway, I don't see any reason why this method shouldn't work albeit with a few more lines than could be achieved using FindBin (TMTOWTDI).

use lib './';

has been working for me with Perl v5.14.2 on a linux box to include files in the same directory as my script.

Perhaps it would work for you to move your lib and bin directories under your script's working directory and try to reference them using

use lib './bin/';

How about:

BEGIN: {
    push @INC, '/full/path/to/lib';
}

To do a relative reference would assume that you're going to keep it in the bin dir, so insert the relative reference there instead.

Related