Can't use Exporter properly - perl

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;

Related

Not able to export methods using Exporter module in perl

I'm trying to export the methods written in my custom module using Exporter perl module. Below is my custom module ops.pm
use strict;
use warnings;
use Exporter;
package ops;
our #ISA= qw/Exporter/;
our #EXPORT=qw/add/;
our #EXPORT_OK=qw/mutliply/;
sub new
{
my $class=shift;
my $self={};
bless($self,$class);
return $self;
}
sub add
{
my $self=shift;
my $num1=shift;
my $num2=shift;
return $num1+$num2;
}
sub mutliply
{
my $self=shift;
my $num1=shift;
my $num2=shift;
return $num1*$num2;
}
1;
Below is the script ops_export.pl using ops.pm
#!/usr/bin/perl
use strict;
use warnings;
use ops;
my $num=add(1,2);
print "$num\n";
when i execute the above script i'm getting below error.
Undefined subroutine &main::add called at ops_export.pl line 8.
I'm not getting why my script is checking in &main package even though i have exported the add in ops.pm using #EXPORT
Where am i going wrong?
ops is a pragma already used by Perl. From the docs:
ops - Perl pragma to restrict unsafe operations when compiling
I don't know what that actually means but that's the issue here.
Rename your module to something else, preferably something with uppercase characters as #simbabque suggests in a comment, because lowercase "modules" are somehow reserved for pragmas (think of warnings or strict).
Also: Calling your add function won't work because you mix up OO code and regular functions. Your add expects three parameters and you supply only two (1 and 2).
When writing OO modules you shouldn't export anything (not even new), i.e.:
package Oops;
use strict; use warnings;
use OtherModules;
# don't mention 'Export' at all
sub new {
...
}
sub add {
...
}
1;
And then in your scripts:
use strict; use warnings;
use Oops;
my $calculator = Oops->new();
my $result = $calculator->add(1, 2);
print $result, "\n"; # gives 3

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.

Modules use each other in cycle. Compilation error in Perl

There are 3 modules, so that they use each other by pattern
a -> b -> c -> a. I cannot compile such case.
For instance,
I get a compilation error
"Throw" is not exported by the LIB::Common::Utils module
Can't continue after import errors at /root/bin/ppm/LIB/Common/EnvConfigMgr.pm line 13
BEGIN failed--compilation aborted at /root/bin/ppm/LIB/Common/EnvConfigMgr.pm line 13.
Utils.pm
use Exporter qw(import);
our #EXPORT_OK = qw(
GetDirCheckSum
AreDirsEqual
onError
Throw);
use LIB::Common::Logger::Log;
Log.pm
use Log::Log4perl;
use LIB::Common::EnvConfigMgr qw/Expand/;
EnvConfigMgr.pm
use Exporter qw(import);
our #EXPORT = qw(TransformShellVars ExpandString InitSearchLocations);
our #EXPORT_OK = qw(Expand);
use LIB::Common::Utils qw/Throw/;
Why doesn't it get compiled and how to make it work?
You need to use require instead of use somewhere in the loop of dependencies so as to delay the binding. It is most convenient with a module that exports nothing, as otherwise you need to write an explicit import call
In your case LIB::Common::Logger::Log doesn't use Export, so putting
require LIB::Common::Logger::Log
into LIB/Common/Utils.pm fixes the problem
You have access to the code that isn't working, and you could have saved us a lot of time by simply showing the malfunctioning code. You ignored two comments asking for more information so I have set up these files
Note that this code does nothing: it simply compiles
LIB/Common/Utils.pm
package LIB::Common::Utils;
use Exporter 'import';
our #EXPORT_OK = qw/
GetDirCheckSum
AreDirsEqual
onError
Throw
/;
require LIB::Common::Logger::Log;
sub GetDirCheckSum { }
sub AreDirsEqual { }
sub onError { }
sub Throw { }
1;
LIB/Common/Logger/EnvConfigMgr.pm
package LIB::Common::EnvConfigMgr;
use Exporter 'import';
our #EXPORT = qw/ TransformShellVars ExpandString InitSearchLocations /;
our #EXPORT_OK = 'Expand';
use LIB::Common::Utils 'Throw';
sub TransformShellVars { }
sub ExpandString { }
sub InitSearchLocations { }
sub Expand { }
1;
LIB/Common/Logger/Log.pm
package LIB::Common::Logger::Log;
use Log::Log4perl;
use LIB::Common::EnvConfigMgr 'Expand';
1;
main.pl
use strict;
use warnings 'all';
use FindBin;
use lib $FindBin::Bin;
use LIB::Common::Utils;

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.