tags:

views:

1664

answers:

5

So lets say I have a dir called foo, and in that I have lib and bin. The scripts in bin need to stuff in lib. So naturally 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?

Edit: lot's of great answers below! But basically it seems like I am Doing It Wrong. The stuff in lib should go to some kind of system library (~/perl/site maybe?) and similarly the stuff in bin should do the same thing. Thanks guys!

+1  A: 

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.

Trey
Why did this get voted down? This seems like the best answer as it will always work...
Frew
This requires modifying all the perl files.
ojblass
A: 

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.

eqbridges
note the question: this doesn't really tell me how to do a relative use.
Frew
You probably want to put the special paths at the front of @INC instead of at the end.
brian d foy
typing too quickly :-)...@frew - the source code is for a fully qualified path -- in my note i explain to insert a relative path.@bdf - Yes you're prb. right, to do that would be an 'unshift' instead of a push.
eqbridges
+11  A: 

The standard "FindBin" module does what you want.

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

"perldoc FindBin" for more.

Michael Cramer
+3  A: 

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 the post below. My understanding of its working was short and so led me to making the first comment which I now retract. Anyway, I don't see any reason why method shouldn't work albeit with a few more lines than could be achieved using FindBin. {TMTOWTDI}

muteW
This recently bit me because rel2abs might end up giving back the wrong Windows path. File::Spec::Win32::rel2abs might end up calling Cwd::getdcwd and return the wrong thing. I had to submit a patch to Archive::Extract to get around this: http://rt.cpan.org/Public/Bug/Display.html?id=43278
brian d foy
FindBin works just fine for locations that aren't in your path. IIRC it fails if there is a (different) file with the same name as your script in your path.
Michael Carman
Your method is actually similar to what FindBin already does, but without the cross-platform love. Really. FindBin is the way to go.
Michael Cramer
Cramer - fixed.
muteW
+2  A: 

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 {
    $realitive_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__ );
Kent Fredric
additonally its probably plausible to get __FILE__ out of caller() . /me ponders
Kent Fredric
nah, go FindBin
singingfish
I had a look at findbin, and it does cover the average use case, but the way it works for some other cases and how it does it in the code is awful. creating a variable at use() time is just really weird to me.
Kent Fredric