Hena has asked for the wisdom of the Perl Monks concerning the following question:

Hello
I'm trying to use modules. However use requires hard path or relative path from users path (path where user gives command not where the perl script actually is). However there seems to no way i can make the perl to include library (modules) dir relative to sript itself.

Eg. My script is in "/work/programs/bin/myscript.pl" and i have module in "/work/programs/perl_modules/Module.pm". Script has "use lib "../perl_modules" Now i'm giving command from "/home/hena" directory and the library include has "../perl_modules" but it is unable to find it.

I found an earlier posting on similar thing, which guided to use use "File::Spec::Functions qw(rel2abs);" and "use lib rel2abs($0);". This adds the script itself into path. But i'm still not able to give it the "../perl_modules" (i could remove script name with `dirname $0`) part.

I posted this question as anonymous monk, but then i lost the question and was unable to find it with search. So sorry for the reposting. Any help would be appreciated. Thanks.

Replies are listed 'Best First'.
Re: Using modules with relative paths
by Corion (Patriarch) on Oct 24, 2003 at 09:32 UTC

    Something that could work would be:

    BEGIN { use File::Spec::Functions qw(rel2abs); use File::Basename; my $homedir = dirname(rel2abs($0)); # let's hope that the homedir is something sane and dosen't # contain curly braces: eval "use lib q{$homedir};"; die $@ if $@; };
    perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web

      Good answer, but one slight modification. The eval around the use line is unneccessary. It would be needed if you were tying to make the "lib" bit dynamic, but the arguments to a module are just a normal perl expression, and can include evaluation. Simply use lib $homedir;. (This also removes the need to die $@ if $@, of course.)


      Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).

        Hmm - on this machine, with this perl, your suggestion does not work, and I think it does not work while used in the same block, as use is a compile time thing:

        Q:\>perl -v This is perl, v5.6.1 built for MSWin32-x86-multi-thread (with 1 registered patch, see perl -V for more detail) (snip-snap) Q:\>perl -e "$foo='bar'; use lib $foo; die join ';',@INC" Empty compile time value given to use lib at -e line 1 ;s:/Os/OSP/OSPI/Perl/lib;s:/Os/OSP/OSPI/Perl/site/lib;. at -e line 1. Q:\>perl -e "BEGIN{$foo='bar'; use lib $foo;} die join ';',@INC" Empty compile time value given to use lib at -e line 1 ;s:/Os/OSP/OSPI/Perl/lib;s:/Os/OSP/OSPI/Perl/site/lib;. at -e line 1. Q:\>perl -e "BEGIN{$foo='bar';} use lib $foo; die join ';',@INC" bar;s:/Os/OSP/OSPI/Perl/lib;s:/Os/OSP/OSPI/Perl/site/lib;. at -e line +1. Q:\>perl -e "BEGIN{my $foo='bar'; eval qq{use lib $foo;}};die join ':' +,@INC" bar:s:/Os/OSP/OSPI/Perl/lib:s:/Os/OSP/OSPI/Perl/site/lib:. at -e line +1.
        perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web
      Yesh!

      This way it works. I could even add a the s/// to go down in path (eg. from "/work/programs/bin" -> "/work/programs". Thanks a lot :).
Re: Using modules with relative paths
by delirium (Chaplain) on Oct 24, 2003 at 14:14 UTC
    I'm not sure if I'm missing some caveats, but I usually attack problems like this by pushing values into the @INC array in a BEGIN block. The code below assumes that the script name (or any directory names) won't contain slashes (/).

    #!/usr/bin/perl -w BEGIN { $0=~s#/?[^/]*$##; $0 ||= '.'; push @INC,$0.'/../perl_modules'; } print "$_\n" for @INC;
Re: Using modules with relative paths
by iburrell (Chaplain) on Oct 24, 2003 at 20:39 UTC
    The other solutions are implementing finding the path of script from $0. There is a module, FindBin, that does this and handles all the edges cases. It is perfect for using it with "use lib" to set @INC. You don't even need a BEGIN block.
    use FindBin; use lib "$FindBin::Bin/../lib";