我有三个文件:
〜/ multiFindBinTest.pl:
use FindBin;
use lib "$FindBin::Bin/mod2";
use pack2;
〜/ MOD1 / pack1.pm
package pack1;
1;
〜/ MOD2 / pack2.pm
use FindBin;
use lib "$FindBin::Bin/../mod1";
use pack1;
package pack2;
1;
如您所见,base.pl使用pack2,而pack2又使用pack1。但是,这是如何不使用FindBin模块的演示:当执行base.pl时,pack2将无法找到pack1,因为它将保留从base获得的“$ FindBin :: Bin”的值特等。
所以我的问题很简单:在perl中是否有一个方法来“使用”一个“使用”另一个模块的模块,所有模块都基于相对于“使用”文件的路径?
答案 0 :(得分:2)
如果您知道所有可能的库根,则只需在命令行中添加它们:
perl -I~/mod1 -I~/mod2 myscript.pl
您可以将它们添加到PERL5LIB环境变量中:
export PERL5LIB=~/mod1:~/mod2
任一方法都将目录放在libaray搜索路径上。
添加个人信息:
如果您希望各个包“声明”其依赖项所在的位置,Perl会提供“lib”编译指示:
use lib '/path/to/lib/directory';
答案 1 :(得分:2)
编译@INC
语句时,模块的位置必须位于use
。最简单的方法是将它们全部添加到调用程序Test.pl
中,如此
use lib "$FindBin::Bin/../mod1", "$FindBin::Bin/../mod2";
然后所有模块的编译将继续进行。
答案 2 :(得分:2)
查找模块文件位置的唯一方法是使用__FILE__
。 FindBin
和$0
都始终引用主脚本文件。
对于模块,这是我能想到的最好的。您对主代码的解决方案很好,但您也可以使用此替代方案。
use strict;
use warnings;
use File::Basename 'fileparse';
use File::Spec;
my $dir;
BEGIN {
$dir = (fileparse(File::Spec->rel2abs(__FILE__)))[1];
}
use lib $dir.'../mod1';
use pack1;
package pack2;
1;
答案 3 :(得分:0)
你没有,但你可以自己做。
package libr;
use strict;
use warnings;
use File::Spec;
sub import {
shift; # invoker
my ( @cands, @missed );
ARGS:
while ( @_ ) {
# Get the next argument from the queued candidates or from the
# arguments
my $raw_path
= my $path
= @cands ? shift @cands : shift
;
# We don't need to worry about this argument unless it has relative
# notation in it.
if ( index( $path, '::' ) > -1 ) {
# split it into parts
my ( $mod, $rest ) = split qr{(?:/(?:\.(?=/))?)+}, $path, 2;
$mod =~ s/^:://; # Allow for one-word relative nodes: 'Word::/';
# Move it from mod notation to file...
my ( $mod_path ) = map { s|::|/|g; $_ } $mod;
my %set;
while ( my $len = length $mod_path ) {
# Remember the more specific path first
$set{ $_ } ||= $mod_path
foreach
# for each key that qualifies, subtract the same
# number of characters from the end of the value
map { substr( $INC{ $_ }, 0, $len - length ) . $rest }
# test each key that it starts with our string
grep { substr( $_, 0, $len ) eq $mod_path }
keys %INC
;
}
continue {
# Check if our separator is in the mod path.
my $mark = rindex( $mod_path, '/' );
last if $mark == -1;
# move the unmatched part of the substring to the
# ending
substr( $rest, 0, 0, substr( $mod_path, $mark ));
# delete it from the path
substr( $mod_path, $mark ) = '';
}
my @sort_order
# We only want the first value...
= map { shift @$_ }
# sort by length of matching path first, then alphabetically
sort { $b->[2] <=> $a->[2] or $a->[1] cmp $b->[1] }
# store a collection of values for sorting:
# lowercase string and length of matching string
map { [ $_ => lc $_ => length $set{ $_ } ] }
keys %set
;
### Assemble list of candidates
@cands = ( @sort_order, map { "$_/$mod_path$rest" } @INC );
next ARGS;
}
# If the path exists
if ( -e $path ) {
# Store the canonical path
push @INC, File::Spec->canonpath( $path );
# And reset tracking arrays
@cands = () if @cands;
@missed = () if @missed;
}
elsif ( @cands ) {
# If we're trying out values, just remember the missed ones.
push @missed, $path;
}
else {
# Else, we're going to tell you we couldn't match the directory
# either to one or to all candidates we tried.
Carp::carp(
"A valid path cannot be determined from '$raw_path': "
. ( @missed > 1 ? do {
local $LIST_SEPARATOR = "\n - ";
push @missed, '', $path;
"\n No paths:@missed\n do not exist!";
}
: "$path does not exist!"
));
@missed = () if @missed;
} # end else
} # end while @_
}
然后你这样使用:
package main;
use A::Long::Package::Name;
use Smart::Comments;
use libr 'A::Long::Package::Name/../Foo', 'Figgy::Puddin';
尝试在单词后翻出@INC
,看看发生了什么。