问题
I'm using custom modules in my scripts and have to store them outside of Perl lib
directory. So in Perl scripts (*.pl
) I use the following block to include them in @INC
:
BEGIN {
use FindBin qw($Bin);
push @INC, "$Bin/../ModulesFolder1";
push @INC, "$Bin/../ModulesFolder2";
}
But I also have to use modules inside of my other Perl modules (*.pm
), and as I understand FindBin
works for scripts only. So I change that block to:
BEGIN {
push @INC, catdir( dirname( $INC{'ThisModule.pm'} ), qw( .. ModulesFolder1 ) );
push @INC, catdir( dirname( $INC{'ThisModule.pm'} ), qw( .. ModulesFolder2 ) );
}
It works but with a little problem. I code in Eclipse with EPIC plugin, and "if you have something in a BEGIN block that causes the compiler to abort prematurely, it won't report syntax errors to EPIC", so that way I loose Perl syntax check in modules.
So, with FindBin
(in scripts) I don't have to use any functions (like catdir
) in BEGIN{}
block, and the syntax check of the following code goes on correctly. Besides, I'd like not to change any environment variables (like PERL5LIB
), so that I could use the scripts on my colleagues' machines without any additional preparations.
What's the proper way of using custom Perl modules inside of other modules, and not interfering with EPIC syntax check at the same time? Or maybe I even should include modules in completely other way?
回答1:
I strongly disagree with modifying @INC
in modules. It causes all kinds of headaches. Let the script (or even the calling process via the PERL5LIB
environment variable) setup @INC
correctly.
script.pl
:
use FindBin qw( $RealBin );
use lib
"$RealBin/../ModulesFolder1",
"$RealBin/../ModulesFolder2";
use ModuleInFolder1;
ModuleInFolder1.pm
:
use ModuleInFolder2; # Works fine.
As for EPIC, do the following:
- Right-click on the project.
- Properties
- Perl Include Path
${project_loc}/ModulesFolder1
, Add to list${project_loc}/ModulesFolder2
, Add to list
(I literally mean the 14 chars ${project_loc}
. That means something to EPIC. It will continue to work even if you move the project.)
PS — $RealBin
is better than $Bin
because it allows you to use a symlink to your script.
PS — __FILE__
is more appropriate than $INC{'ThisModule.pm'}
.
回答2:
Not sure about Eclipse, but you can use use lib (will probably not work, it changes @INC
at compile time) or set the environment variable PERL5LIB
to point to your library folder(s).
回答3:
Set up PERL5LIB
environment variable. Every time you use or require, Perl will check all directories listed in it.
Alternatively, place all necessary custom modules under script's directory, so you can use relative paths in use lib
. It will also allow you to quickly make a bundle to transfer everything to another PC by just packing recursively from top-level directory.
回答4:
Another solution (from my colleague) - a change to be made in the module:
sub path_to_current_module() {
my $package_name = __PACKAGE__ .'.pm';
$package_name =~ s#::#/#g;
for my $path ( @INC ) {
# print "\$path == '$path'\n";
if ( -e catfile( $path, $package_name ) ) {
return $path;
}
}
confess;
}
BEGIN {
my $path_to_current_module = path_to_current_module();
push @INC, catdir( $path_to_current_module, qw( .. ModulesFolder1 ) );
push @INC, catdir( $path_to_current_module, qw( .. ModulesFolder2 ) );
}
It seems that the old way (described in the question) Perl couldn't locate current module name in @INC
- that's why perl -c
was interrupted by error inside of the BEGIN
block. And the described sub helps it to determine the real path to the current module. Besides, it doesn't depend on the current file name and can be copied to another module.
来源:https://stackoverflow.com/questions/11687018/a-proper-way-of-using-perl-custom-modules-inside-of-other-perl-modules