Perl Module Creation & Usage - Undefined subroutine - perl

I am trying to create & use modules in a new script I'm doing but I'm not familiar with modules yet.
I've been following some tutorials, and even if I have the "almost" exact same code as in the tutorial, it doesn't work and when I run my test-script I get the following error:
Undefined subroutine &main::func1 called at ../../bin/fftg.pl line 21.
Here is my main script :
#!/usr/bin/perl
# ......
# comments here
# ......
use strict;
use warnings;
use File::Basename qw(dirname);
use Cwd qw(abs_path);
use lib dirname(dirname abs_path $0) . '/lib';
use FFTG::PID qw(:DEFAULT);
print func1(10,20);
and here is the module, created as file lib/FFTG/PID.pm :
package PID;
use strict;
use warnings;
use Exporter;
our $VERSION = 1.00;
our #ISA = qw(Exporter);
our #EXPORT = qw(&func1 &func2); # I tried all lines without &
our #EXPORT_OK = qw(&func1 &func2); # I tried all lines without &
our %EXPORT_TAGS = ( DEFAULT => [qw(&func1)],
Both => [qw(&func1 &func2)]);
sub func1
{
my ($x, $y) = #_;
return $x + $y;
}
sub func2
{
return "tata\n";
}
1;
what am I doing wrong please ?
I tried to load the thing using :
use FFTG::PID qw(:DEFAULT);
use FFTG::PID;
use FFTG::PID qw(funct1);
use FFTG::PID qw(&funct1);
nothing works (same error)
I also tried to modify the module, modifying these lines removing or adding the & :
our #EXPORT = qw(func1 func2);
our #EXPORT_OK = qw(func1 func2);
same problem
any hints ?
my folders & files are :
MIF/root#sm1p0003vmo /wminfs/mc/projects/FFTGv2: pwd
/wminfs/mc/projects/FFTGv2
MIF/root#sm1p0003vmo /wminfs/mc/projects/FFTGv2: ls -al bin/fftg.pl
-rwxr-x--- 1 root root 545 May 18 09:49 bin/fftg.pl
MIF/root#sm1p0003vmo /wminfs/mc/projects/FFTGv2: ls -al lib/FFTG/PID.pm
-rw-r----- 1 root root 344 May 18 09:37 lib/FFTG/PID.pm
MIF/root#sm1p0003vmo /wminfs/mc/projects/FFTGv2:
thanks
regards,

There are a few errors, and a few things that can be done better.
The module name needs to match its (relative) location, so: package FFTG::PID;
There can be no & when listing subroutines for EXPORTs in the module; those should be names and the & isn't a part of the name. From use pragma (my emphasis)
Imports some semantics into the current package from the named module
All-caps names are a risky idea as they may be taken, and DEFAULT cannot be used here
It is generally a good advice to use #EXPORT_OK, and not #EXPORT.
Finally, the line that sets up lib is asking for trouble. Use FindBin.
Package lib/FFTG/PID.pm
package FFTG::PID;
use strict;
use warnings;
use Exporter qw(import);
our $VERSION = 1.00;
our #EXPORT_OK = qw(func1 func2);
our %EXPORT_TAGS = (
default => [ qw(func1) ],
both => [ qw(func1 func2) ]
);
sub func1
{
my ($x, $y) = #_;
return $x + $y;
}
sub func2
{
return "tata\n";
}
1;
where I've also replaced the explicit setup of #ISA with the Exporter'simport method.
The main program
use strict;
use warnings;
use feature qw(say);
use FindBin qw($RealBin);
use lib "$RealBin/lib";
use FFTG::PID qw(:default);
say func1(10,20);
It prints a line with 30.

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;

Perl: script and module calling a second module

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

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;

Unable to load Perl subpackage

I can't work out why I am unable to access a subpackage:
mbzdb:
#!/usr/bin/perl -w
use lib "./lib";
use MbzDb::Instance;
my $instance = new MbzDb::Instance();
$instance->startFromCommandLine();
lib/MbzDb/Instance.pm:
#!/usr/bin/perl -w
package MbzDb::Instance;
use strict;
use warnings;
use Getopt::Long;
require Exporter;
our #ISA = qw(Exporter);
our #EXPORT = qw(new startFromCommandLine);
sub new {
my $class = shift;
return bless {}, $class;
}
sub startFromCommandLine {
my $self = shift;
}
If I use the same code in lib/MbzDb.pm the export works correctly. What am I doing wrong?
The error given is:
Can't locate object method "new" via package "MbzDb::Instance" (perhaps you forgot to load "MbzDb::Instance"?) at ./mbzdb line 6.
Try using the excellent FindBin module.
use FindBin;
use lib $FindBin::Bin . '/lib';
use MbzDb::Instance;
This works if your structure looks like this:
mbzdb
lib/
MbzDb/
Instance.pm

Perl library to avoid redefining an already defined function

I have two perl module files like :
is_date_holiday.pl :
use strict;
use warnings;
sub IsDateHoliday
{
...
}
1
calc_prev_working_date_mult.pl :
use strict;
use warnings;
require "is_date_holiday.pl"; # IsDateHoliday
sub CalcPrevWorkingDateMult
{
...
}
1
On using them both in a perl file like :
require "is_date_holiday.pl"; # IsDateHoliday
require "calc_prev_working_date_mult.pl" # CalcPrevWorkingDateMult
It complains that I am redefining the function IsDateHoliday
How can do an equivalent of #ifndef ?
You don't actually have modules, but you should.
IsDateHoliday.pm:
package IsDateHoliday;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT_OK = qw( IsDateHoliday );
our %EXPORT_TAGS = ( all => \#EXPORT_OK );
sub IsDateHoliday
{
...
}
1;
CalcPrevWorkingDateMult.pm:
package CalcPrevWorkingDateMult;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT_OK = qw( CalcPrevWorkingDateMult );
our %EXPORT_TAGS = ( all => \#EXPORT_OK );
use IsDateHoliday qw( :all );
sub CalcPrevWorkingDateMult
{
...
}
1;
main.pl:
use IsDateHoliday qw( :all );
use CalcPrevWorkingDateMult qw( :all );
Really you should create packages for these and then use them. That will eliminate the issues with redefining because you can then import what you need and use won't import stuff twice.
package IsDateHoliday;
use strict;
use warnings;
use Exporter;
our #ISA = qw(Exporter);
our #EXPORT = qw(IsDateHoliday);
sub IsDateHoliday {
#...
}
1; # not a typo, Perl needs modules to return true
Name the file "IsDateHoliday.pm" then when you need it:
use strict;
use lib '.'; # to include the local directory
use IsDateHoliday;
Same treatment for the other one.
Of course one might question why you don't just use Date::Calc from CPAN. (Might not have holidays but I'm sure something else on CPAN does!)
Although it'd be best to change to use over require, which will check to see if it's already been loaded first, if you really wanted to write C in perl, likely the closest to what you're trying to do would be to just set some variable, and check to see if exists, but you have to hide the subroutine definition in an eval.
# in the included file:
my $DateHolidayLoaded;
if ( !$DateHolidayLoaded ) {
eval {
sub IsDateHoliday { ... }
$DateHolidayLoaded = 1;
};
}
You can test for a function's existance, too, but you have to specify what namespace to use ... and in this case, it'd be 'main' :
if ( ! defined( main->can( 'IsDateHoliday' ) ) ) { require 'is_date_holiday.pl' }
But this will only work in the file doing the include; if you do this test in a file with the subroutine definition, it'll always be true.