Perl: script and module calling a second module - perl

I have the following:
Module1
package module1;
require Exporter;
our #ISA = qw(Exporter);
our #EXPORT = qw(<list of subs within>);
use Module2;
sub M1S1 ()
{
$x = M2S1();
}
Module 2
package module2;
require Exporter;
our #ISA = qw(Exporter);
our #EXPORT = qw(<list of modules within>);
sub M2S1()
{
...
}
sub M2S2()
{
...
}
Script
use Module2;
use Module1;
$y = M1S1();
$z = M2S2();
When the script calls a sub in Module 1 which in turn calls a sub in Module 2, the sub is not found, even though the script can call those subs directly.
I'm not a beginner to Perl by any means, but I've never fully gotten the hang of modules. Our environment has gotten very dependent on module2, so I don't want to make any changes that would require changing all the scripts that use it. Module1 has limited use so I can make changes to it if necessary.

The file name, the name in the package directive, and the name in the use statement must match, and that includes case.
Module1.pm
package Module1;
use Module1;
Or if you had a non-flat namespace,
Foo/Bar.pm
package Foo::Bar;
use Foo::Bar;
Note that you can have similar problems when you have two exporting modules that use each other (directly or indirectly), but that doesn't seem to the case.
$ cat Module1.pm
package Module1;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT = qw( M1S1 );
use Module2;
sub M1S1 { M2S1() }
1;
$ cat Module2.pm
package Module2;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT = qw( M2S1 M2S2 );
sub M2S1 { "M2S1" }
sub M2S2 { "M2S2" }
1;
$ cat script.pl
#!/usr/bin/perl
use strict;
use warnings;
use Module2;
use Module1;
print(M1S1(), "\n");
print(M2S2(), "\n");
$ ./script.pl
M2S1
M2S2

Related

Can't use Exporter properly

I've wasted many days on a larger block of code, containing Exporter statements, which used to work about a year ago. Several variations on this have failed, including an install of ./FOO/BAR/Foobar.pm which signaled success.
I am using Windows 10, Perl v5.26.0, built for MSWin32-x64-multi-thread
Caller.pl
#!/usr/bin/perl
use lib ".";
use lib "./FOO/BAR";
use strict;
use warnings;
use FOO::BAR::Foobar;
print "try FOO::BAR::Foobar::foo()\n";
FOO::BAR::Foobar::foo(); # perl can't find this
print "try foo()\n";
foo(); # errors out - can't find &main::foo
print "done\n";
./FOO/BAR/Foobar.pl
#!/usr/bin/perl -w
use strict;
use warnings;
package Foobar;
our($VERSION , #ISA , #EXPORT , #EXPORT_OK , %EXPORT_TAGS , $FOO);
BEGIN {
require Exporter;
#ISA = qw(Exporter);
#EXPORT_OK = qw(foo);
}
sub foo {
print "Loaded\n";
$FOO = q{some val};
}
1;
Execution dump
perl Caller.pl
try FOO::BAR::Foobar::foo()
Undefined subroutine &FOO::BAR::Foobar::foo called at Caller.pl line 12.
What's going on? Should I abandon any use of Exporter? But then how to link functions across modules?
There are three things going wrong:
With FOO::BAR::Foobar::foo(): There is no such sub, there is only Foobar::foo().
With foo(): use FOO::BAR::Foobar; is the equivalent of BEGIN { require FOO::BAR::Foobar; FOO::BAR::Foobar->import() }, but there is no method import available in the package FOO::BAR::Foobar, since you're inheriting Exporter into the package Foobar.
With foo(): You're using #EXPORT_OK instead of #EXPORT, which means that you need to explicitly import foo, but you're not doing that in use FOO::BAR::Foobar;.
So two things are needed to fix this:
As already pointed out in the comment by #HåkonHægland, change package Foobar; to package FOO::BAR::Foobar;.
Change use FOO::BAR::Foobar; to use FOO::BAR::Foobar qw/foo/;.
Then the code you've shown will work - there's no need to abandon Exporter. I'd just recommend a different style of using Exporter: Instead of inheriting via #ISA, just import import into your package. Here's how I would have written your file ./FOO/BAR/Foobar.pm:
package FOO::BAR::Foobar;
use strict;
use warnings;
use Exporter 'import';
our #EXPORT_OK = qw(foo);
our $FOO;
sub foo {
print "Loaded\n";
$FOO = q{some val};
}
1;

Multiple package with exporter in Perl

I'm trying to get familiar with Perl exporter, the issue i am facing is whatever I try I cannot use exporter with modules containing multiple packages in it. What am I missing below?
MyModule.pm
use strict;
use warnings;
package Multipackage1;
use Exporter;
our #ISA = qw(Exporter);
our #EXPORT = qw(test1);
sub test1 {
print "First package\n";
}
1;
package Multipackage2;
use Exporter;
our #ISA = qw(Exporter);
our #EXPORT = qw(test2);
sub test2 {
print "Second package\n";
}
1;
package Multipackage3;
use Exporter;
our #ISA = qw(Exporter);
our #EXPORT_OK = qw(test3);
sub test3 {
print "Third package\n";
}
1;
MyMainFile.pl
#!/usr/bin/perl
use strict;
use warnings;
use Multipackage;
use Multipackage qw(test3);
print "Calling first package:\n";
test1();
print "Calling second package:\n";
test2();
print "Calling third package:\n";
test3();
I getting test1 is not part of the main package.
Thanks in advance.
The use calls require, which looks for a file with the package name (with / for :: and + .pm).
So require the actual file with packages instead and then import from packages.
main.pl
use warnings;
use strict;
require MyModule;
import Multipackage1;
import Multipackage2;
import Multipackage3 qw(test3);
print "Calling first package:\n";
test1();
print "Calling second package:\n";
test2();
print "Calling third package:\n";
test3();
In the MyModule.pm, place each package in its own block to provide scope for lexical variables, since package doesn't do that, or use package Pack { ... } since v5.14. There is no need for all those 1s, and you may pull use Exporter; out of the blocks.
Output
Calling first package:
First package
Calling second package:
Second package
Calling third package:
Third package
Better yet, replace our #ISA = qw(Exporter); with use Exporter qw(import); for
use strict;
use warnings;
package Multipackage1 {
use Exporter qw(import);
our #EXPORT = qw(test1);
sub test1 { print "First package\n" }
}
...
1;
with the same output.
Note that putting multiple packages in one file is normally not needed and not done.

Specal Handling of Base.pm?

I create a module called Base.pm in the same directory as the Perl program that wants to use it but the module doesn't seem to be loaded. Change the name of the module to anything other than Base and things work just fine. What is special about Base.pm and how does one override this behavior? Thanks for any insight.
package Base;
use strict;
use Exporter;
use vars qw($VERSION #ISA #EXPORT #EXPORT_OK %EXPORT_TAGS);
$VERSION = 1.00;
#ISA = qw(Exporter);
#EXPORT = qw(func);
sub func { return "foo"; }
1;
with
use Base;
print func();
yields
Undefined subroutine &main::func called at test0.pl line 2.
whereas
package Case;
use strict;
use Exporter;
use vars qw($VERSION #ISA #EXPORT #EXPORT_OK %EXPORT_TAGS);
$VERSION = 1.00;
#ISA = qw(Exporter);
#EXPORT = qw(func);
sub func { return "foo"; }
1;
with
use Case;
print func();
yields
foo.
base.pm is a core system "pragma" module (these days, it's deprecated for parent.pm)
use base 'MyBaseClass'; # Same as: our #ISA = ( 'MyBaseClass' );
It's probably a Windows case thing. Perl looks for "Base.pm", but windows returns "base.pm". When you named it "anything other than Base", you probably didn't rename it to another Perl module.
One way you can check this is to run the following:
use Data::Dumper
print a dump of %INC (a map of all loaded modules and where they were loaded from)
use Data::Dumper;
...
use Base;
...
print Dumper( \%INC );
Look for 'base.pm' or 'Base.pm' to see what Perl loaded.
Inspect %INC to see what's actually being loaded:
use Base;
print $INC{'Base.pm'};
Outputs:
/Users/miller/perl5/perlbrew/perls/perl-5.20.0/lib/5.20.1/Base.pm
I'm on a non-case sensitive OSX partition, so this file corresponds to the base pragma.
To avoid this type of issue, give your projects a private namespace. This way there's less risk of conflicting with a current or future Perl Core or CPAN module:
package MyProject::Base;

Why don't functions from package A get imported into package B when they recursively call each other?

I'm trying to use two packages and call functions from one to other, but I've got this error:
Undefined subroutine &module2::method_1_2 called at module2.pm line 20.
Is there any way to call functions from one package to the other one without getting this error?
Thanks in advance.
xabi
exec error:
./test.pl
method_1_1
method_2_1
method_2_2
Undefined subroutine &module2::method_1_2 called at module2.pm line 20.
Sample code (test.pl):
#!/usr/bin/perl
use strict;
use module1;
use module2;
method_1_1();
method_2_2();
module1.pm
package module1;
use strict;
use module2;
require Exporter;
use vars qw(#ISA #EXPORT);
#ISA = qw(Exporter);
#EXPORT = qw( method_1_1 method_1_2 );
sub method_1_1
{
print "method_1_1\n";
method_2_1();
}
sub method_1_2
{
print "method_1_2\n";
}
1;
module2.pm:
package module2;
use strict;
use module1;
require Exporter;
use vars qw(#ISA #EXPORT);
#ISA = qw(Exporter);
#EXPORT = qw( method_2_1 method_2_2 );
sub method_2_1
{
print "method_2_1\n";
}
sub method_2_2
{
print "method_2_2\n";
method_1_2();
}
1;
The problem is that the very first thing module1 does is to use module2. That means all of module2 is read and executed while module1 is still compiling.
The next thing to happen is that module2 does use module1. Because module1 has been found and put into %INC Perl doesn't execute it again, and just does module1->import to fetch the exported symbols.
But of course module1 has in fact barely started compiling, and #module1::EXPORT doesn't even exist, never mind about its two subroutines. That makes Exporter import nothing at all into module2, so when it comes to make the call method_1_2() it knows nothing about it.
The cleanest way to fix this is to do the import after the compilation (including all the use statements and BEGIN blocks) but before runtime. Perl's INIT block is ideal for this, and we can get the code working by changing the modules to the form below. I have shown only module2 here, as the pattern of calls means this is all that's needed to fix this particular problem, but the general case needs the equivalent change to all cooperating modules.
package module2;
use strict;
use warnings;
use module1;
INIT { module1->import }
use base 'Exporter';
our #EXPORT = qw( method_2_1 method_2_2 );
sub method_2_1 {
print "method_2_1\n";
}
sub method_2_2 {
print "method_2_2\n";
method_1_2();
}
1;
The problem is that you assign to #EXPORT after it was already used. The following is copied from Mini-Tutorial: Mutual Use of Exporting Modules
[ The need to use this technique is a very strong indicator of a design flaw in your system, but I recognize that the resources are not always available to fix design flaws. ]
If ModA uses ModB, ModB uses ModA, and ModA or ModB imports symbols from the other, one needs to pay attention to code execution order. The best way I've found to avoid problems is to setup Exporter before loading any other module.
# ModA.pm
package ModA;
use strict;
use warnings;
use Exporter qw( import );
BEGIN { our #EXPORT_OK = qw( ... ); }
use This;
use ModB;
use That;
...
1;
# ModB.pm
package ModB;
use strict;
use warnings;
use Exporter qw( import );
BEGIN { our #EXPORT_OK = qw( ... ); }
use This;
use ModA;
use That;
...
1;
Interesting, I am not sure why method_1_2 isn't being exported into the module2 namespace, but you can get around this by explicitly referencing the package:
module1.pm
package module1;
use strict;
use warnings;
use module2 (); #don't import methods
use base 'Exporter';
our #EXPORT = qw( method_1_1 method_1_2 );
sub method_1_1
{
print "method_1_1\n";
module2::method_2_1();
}
sub method_1_2
{
print "method_1_2\n";
}
1;
module2.pm
package module2;
use strict;
use warnings;
use module1 (); #don't import methods
use base 'Exporter';
our #EXPORT = qw( method_2_1 method_2_2 );
sub method_2_1
{
print "method_2_1\n";
}
sub method_2_2
{
print "method_2_2\n";
module1::method_1_2();
}
1;
Okay, I think I see what is going on, but take this with a grain of salt. The use function is effectively a BEGIN block and BEGIN blocks run as soon as they are parsed, so the code looks like this in execution order.
perl starts parsing test.pl
it sees use module1; so it loads module1.pm and starts parsing it
perl sees use module2; in module1.pm so it loads module2.pm and starts parsing it
At this point, the functions in module1 do not yet exist, so they can't be imported
parsing continues
Something Borodin said tipped me off to the best solution: "#module1::EXPORT doesn't even exist". The problem here is that the #EXPORT variable doesn't exist. This can be fixed by putting it in a BEGIN block:
module1.pm
package module1;
use strict;
use warnings;
use base 'Exporter';
BEGIN {
our #EXPORT = qw( method_1_1 method_1_2 );
}
use module2;
sub method_1_1
{
print "method_1_1\n";
module2::method_2_1();
}
sub method_1_2
{
print "method_1_2\n";
}
1;
module2.pm
package module2;
use strict;
use warnings;
use base 'Exporter';
BEGIN {
our #EXPORT = qw( method_2_1 method_2_2 );
}
use module1;
sub method_2_1
{
print "method_2_1\n";
}
sub method_2_2
{
print "method_2_2\n";
method_1_2();
}
1;
IMPORTANT NOTE: I do not believe prototypes in module1 will be honored in any of these cases (and I don't see how they could be since module2 gets compiled before module1, so it can't know the prototypes exist). This is yet another argument to never use prototypes.

Why can't Perl find the library in my t/ directory?

I have a .pm file in my current directory /t, and I inserted this line of code:
use lib qw(.);
Then I inserted this line of code
use TestUtil.pm;
where TestUtil.pm is in the current directory, but I keep getting this error:
Can't locate TestUtil.pm in #INC (#INC contains: . ........ ( Note that #INC contains the current directory)
TestUtil.pm:
package TestUtil;
use strict; use warnings;
BEGIN { use Exporter (); use vars qw( $VERSION #ISA #EXPORT );
# Set the version for version checking
$VERSION = 1.00; #ISA = qw( Exporter ); #EXPORT = qw(_a ); }
use vars qw( $VERSION #ISA #EXPORT );
sub _a { return 1; }
test_XXX.t:
use lib qw(.); use strict; use warnings;
use TestUtil;
What am I doing wrong?
If you are running your test like so:
prove --lib t
Then your working directory is actually a level above t/
So in your package (source filet/TestUtil.pm)
package t::TestUtil;
use strict; use warnings;
And in your test_XXX.t
use lib '.';
use t::TestUtil;
I've seen it done this way in several CPAN modules.
Try removing the .pm from the module name in the "use ..." statement.
In TestUtil.pm
package TestUtil;
use strict; use warnings;
BEGIN { use Exporter (); use
vars qw( $VERSION #ISA #EXPORT
);
# Set the version for version
checking
$VERSION = 1.00; #ISA =
qw( Exporter ); #EXPORT = qw(_a
); }
use vars qw( $VERSION #ISA #EXPORT );
sub _a { return 1; }
In test_XXX.t
use lib qw(.);
use strict;
use warnings;
use TestUtil;
Have you declared the TestUtil.pm as a TestUtil module?
# in your TestUtil module...
package TestUtil;
EDIT:
Is your Perl module (TestUtil.pm) returning a status? Try adding this to the end of the TestUtil.pm file:
1;