Compilation error depends on 'use' order - perl

I have these three files
Constants/Requests.pm
#!/usr/bin/perl
use strict;
use base 'Exporter';
use constant MR_NOACTION => 0;
use constant MR_START => 1;
use constant MR_STOP => 2;
our #EXPORT = (
'MR_NOACTION',
'MR_START',
'MR_STOP'
);
1;
JobManDB.pm
#!/usr/bin/perl
package JobManDB;
use strict;
use warnings;
use constant WEB_DB_FILE => "db/web.db";
use constant MASTER_DB_FILE => "db/master.db";
use Constants::Requests;
sub new
{
print "Ahoj: " . MR_NOACTION . "\n";
...
Master.pm
#!/usr/bin/perl
package Master;
use strict;
use warnings;
use Time::HiRes qw( usleep );
use Data::Dumper;
use JobManDB; # use #1
use Constants::Requests; # use #2
...
Program as posted is working, if but if I swith use #1 with use #2 the compilation fails with error:
Bareword "MR_NOACTION" not allowed while "strict subs" in use at lib/JobManDB.pm line 26.
(line 26 is the line in 'new' subroutine). I would like to know why. Thank you.
EDIT:
Another issue is, that if I add line package Requests; at the beginning of Requests.pm, the compilation fails with the same error but independently on order of 'uses'.

The Requests.pm file is missing its package declaration, package Constants::Requests;.

Related

Undefined subroutine &main::add called at ex1.pl line 4

I have a perl Module
MyMathLib.pm
package MyMathLib;
require Exporter;
#ISA = qw/EXPORTER/;
#EXPORT = qw/add/;
sub add
{
$_[0] + $_[1];
}
1;
Ex1.pl
#!usr/bin/perl
#
use MyMathLib;
print add(1,2);
I am getting the below error:
Undefined subroutine &main::add called at ex1.pl line 4.
What could be the reason?
It's an Exporter not an EXPORTER.
If you include
use strict;
use warnings;
in your scripts you'll activate more checks that would have shown you a clue to the problem:
Can't locate package EXPORTER for #MyMathLib::ISA at Ex1.pl line 5.
Undefined subroutine &main::add called at Ex1.pl line 6.

access variables from different files in Perl

file1.pl
package ba;
#!/usr/bin/perl
use strict;
use warnings;
our $base_addr = 0x48;
file2.pl
package oa;
#!/usr/bin/perl
use strict;
use warnings;
our $offset_addr = 0;
file3.pl
#!/usr/bin/perl
do "file1.pl"
do "file2.pl"
my $final_val;
$final_val = $ba::base_addr + $oa::offset_addr;
printf "base_addr = 0x%0x\n", $ba::base_addr;
printf "offset_addr = 0x%0x\n", $oa::offset_addr;
printf "final addr = 0x%0x\n", $final_val;
ERRORS### ->
Argument "0x48" isn't numeric.
Use of uninitialized value.
Use of uninitialized value in addition.
Two major errors, both of which are found by using use strict; use warnings;. Always do so. (You used it in your modules, but not in your script.)
You correctly use $ba::base_addr in one spot, but then you proceeded to use non-existent variable $base_addr shortly afterwards.
You can only access $ba::base_addr as $base_addr if the current package is ba, or if you create an alias to it named $base_addr.
You either need to use $ba::base_addr consistently, or you need to export the variable to the using module. (This is one way to the alias I mentioned.)
You never assign a value to $ba::base_addr and $oa::offset_addr, so Perl gives you warnings when you attempt to add them ("not numeric") and when you try to print them ("uninitialized").
Some other problems we'll fix at the same time:
A module must return a true value, which is to say the last expression evaluated must evaluate to something true. It's thus standard to end a module with 1; (This applies to do too for reliable error detection: do $qfn or die $# || $!;.)
You should be using require instead of do since the files have a package declaration. It would be even better if you renamed them to .pm and used use.
The name of a module should match it's package declaration. If it contains package ba;, the file should be named ba.pm.
#! is only meaningful if 1) they are the first two characters of the file, and 2) if the file is provided to the OS for execution. Neither of those are the case for your modules.
ba.pm:
package ba;
use strict;
use warnings;
our $base_addr = 123;
1;
oa.pm:
package oa;
use strict;
use warnings;
our $offset_addr = 456;
1;
script.pl:
#!/usr/bin/perl
use strict;
use warnings;
use ba qw( );
use oa qw( );
my $final_val = $ba::base_addr + $oa::offset_addr;
print "base_addr = $ba::base_addr\n";
print "offset_addr = $oa::offset_addr\n";
print "final addr = $final_val\n";
You could avoid saying the package name everywhere if you exported the variables, and mentioned earlier.
ba.pm:
package ba;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT_OK = qw( $base_addr );
our $base_addr = 123;
1;
oa.pm:
package oa;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT_OK = qw( $offset_addr );
our $offset_addr = 456;
1;
script.pl:
#!/usr/bin/perl
use strict;
use warnings;
use ba qw( $base_addr );
use oa qw( $offset_addr );
my $final_val = $base_addr + $offset_addr;
print "base_addr = $base_addr\n";
print "offset_addr = $offset_addr\n";
print "final addr = $final_val\n";
It's typically bad form to export variables, though. It's usually far better to create accessors.
ba.pm:
package ba;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT_OK = qw( base_addr );
my $base_addr = 123;
sub base_addr { $base_addr }
1;
oa.pm:
package oa;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT_OK = qw( offset_addr );
my $offset_addr = 456;
sub base_addr { $base_addr }
1;
script.pl:
#!/usr/bin/perl
use strict;
use warnings;
use ba qw( base_addr );
use oa qw( offset_addr );
my $final_val = base_addr() + offset_addr();
print "base_addr = ".base_addr()."\n";
print "offset_addr = ".offset_addr()."\n";
print "final addr = $final_val\n";
You need to rename your files, add return values and include them using use. Here:
file1.pm
package ba;
use strict;
use warnings;
our $base_addr = 17;
1;
file2.pm
package oa;
use strict;
use warnings;
our $offset_addr = 19;
1;
file3.pl
#!/usr/bin/perl
use file1;
use file2;
my $final_val;
$final_val = $ba::base_addr + $oa::offset_addr;
print "base_addr = $ba::base_addr\n";
print "offset_addr = $oa::offset_addr\n";
print "final addr = $final_val\n";

How to print the elements of a hash that is defined in another file? [duplicate]

This question already has answers here:
declaring a hash table in one file and using it in another in Perl
(4 answers)
Closed 9 years ago.
How to print the elements of a hash that is defined in another file?
file1.pl:
#!/usr/bin/perl
use strict;
use warnings;
our %hash =
("Quarter" , 25,
"Dime" , 10,
"Nickel" , 5 );
file2.pl:
#!/usr/bin/perl
use strict;
use warnings;
require "file1.pl"
foreach (sort keys %hash){
print "$hash{$_}\n";
}
Output:
Global symbol "%hash" requires explicit package name.
Global symbol "%hash" requires explicit package name.
Kindly help
Modules need a package statement and must end with a true value. (It currently returns a true value, but I like to use an explicit 1;.) It's better to give them the .pm extension.
# MyConfig.pm
package MyConfig;
use strict;
use warnings;
our %hash = (
"Quarter" => 25,
"Dime" => 10,
"Nickel" => 5,
);
1;
Now, if you left it at that, you'd need to use %MyConfig::hash instead of %hash. So we need to export the var from the module to the user's namespace.
# MyConfig.pm
package MyConfig;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT = qw( %hash );
our %hash = (
"Quarter" => 25,
"Dime" => 10,
"Nickel" => 5,
);
1;
So on to the script:
#!/usr/bin/perl
use strict;
use warnings;
use MyConfig;
for (sort keys %hash) {
print "$hash{$_}\n";
}
use MyConfig; does a require (if necessary) and an import. The latter brings the variables and subs listed in #EXPORT into the current namespace.
Ignoring the fact that the code you posted was many edits away from actually giving the error messages you claimed, your problem is that you do not declare %hash in file2.pl. Since that file uses the strict pragma (which is a good thing), it gives this fatal error. To overcome this, declare the hash:
our %hash;
require 'file1.pl';
#... etc.
However, if you are trying to use require as a means of loading a configuration file, there are many better ways. For example Config::Any.

Accessing value of a global variable using require?

Is it possible to access value of a global variable declared, in another perl script using require?
eg.
Config.pl
#!/usr/bin/perl
use warnings;
use strict;
our $test = "stackoverflow"
Main.pl
#!/usr/bin/perl
use warnings;
use stricts;
require "Config.pl"
print "$test\n";
print "$config::test\n";
sure. The way you have suggested almost works. Try:
Config.pl:
use warnings;
use strict;
our $test = "stackoverflow";
and the main program:
#!/usr/bin/perl
use warnings;
use strict;
require "Config.pl";
our $test;
print "$test\n";
When you call require, the file is executed in the same namespace as the caller. So without any namespaces or my declarations any variables assigned will be globals, and will be visible to the script.
You need to declare the variable $test in Main.pl by writing
our $test;
as you do in Config.pl. Then everything will work as you expect.
Better to use a module:
MyConfig.pm: (There's a core package called "Config" already.)
package MyConfig;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT_OK = qw( $test );
our %EXPORT_TAGS = ( ALL => \#EXPORT_OK );
our $test = "stackoverflow";
1;
main.pl:
use strict;
use warnings;
use MyConfig qw( :ALL );
print "$test\n";

How can I create a Perl variable name based on a string?

In Perl, is it possible to create a global variable based on a string?
E.g., if I had a function like:
sub create_glob_var {
my ($glob_var_str) = #_;
# something like this ( but not a hash access).
our ${$glob_var_str};
};
and I called it like:
create_glob_var( "bar" );
How could I modify create_glob_var to actually create a global variable called $bar?
My project is using perl 5.8.5.
EDIT
The following doesn't work:
use strict;
BEGIN {
sub create_glob_var {
my ($glob_var_str) = #_;
no strict 'refs';
$$glob_var_str = undef; # or whatever you want to set it to
}
create_glob_var("bah");
};
$bah = "blah";
Produces:
Variable "$bah" is not imported at /nfs/pdx/home/rbroger1/tmp2.pl line 12.
Global symbol "$bah" requires explicit package name at /nfs/pdx/home/rbroger1/tmp2.pl line 12.
Execution of /nfs/pdx/home/rbroger1/tmp2.pl aborted due to compilation errors.
NOTE I realize that using global variables causes ozone depletion and male pattern baldness. I'm trying to clean up some legacy code that is already completely infected with the use of global variables. One refactor at a time...
If you are trying to clean up old code, you can write a module which exports the required variable(s). Every time you feel the need to invoke create_glob_var, instead add a variable to this package and put that in the import list.
This will help you keep track of what is going on and how variables are being used.
package MyVars;
use strict; use warnings;
use Exporter 'import';
our($x, %y, #z);
our #EXPORT_OK = qw( $x %y #z );
The script:
#!/usr/bin/perl
use strict;use warnings;
use MyVars qw( $x %y #z );
$x = 'test';
%y = (a => 1, b => 2);
#z = qw( a b c);
use Data::Dumper;
print Dumper \($x, %y, #z);
Output:
$VAR1 = \'test';
$VAR2 = {
'a' => 1,
'b' => 2
};
$VAR3 = [
'a',
'b',
'c'
];
sub create_glob_var {
my ($glob_var_str) = #_;
no strict 'refs';
$$glob_var_str = undef; # or whatever you want to set it to
}
The no strict 'refs' is only necessary if use strict is in effect, which it always should be.
Addendum:
If you're asking if there's a way to write a subroutine create_glob_var such that the following code will succeed:
use strict;
create_glob_var("bar");
$bar = "whatever";
...then the answer is "No." However, Perl's vars pragma will do what you want:
use strict;
use vars qw($bar);
$bar = "whatever";
But this is kind of old-style Perl coding. Nowadays, one would typically do this:
use strict;
our $bar = "blah";
our can also just declare global variables that can be freely used later:
our ($foo, #bar, %baz);
# ...
$foo = 5;
#bar = (1, 2, 3);
%baz = (this => 'that');
Try looking at this question:
Does Perl have PHP-like dynamic variables?
In brief, it seems like you should be able to do $$glob_var_str = "whatever";
You would have to use an eval, but that's generally considered evil. Something like:
eval("$glob_var_str = \#_;");
EDIT
Just verified that you can only do this without the my and with no strict refs.
The vars pragma already does the heavy lifting for what you want, so put it to work:
#! /usr/bin/perl
use warnings;
use strict;
use vars;
BEGIN { vars->import(qw/ $bah /) }
$bah = "blah";
print $bah, "\n";
If you prefer to spell it create_glob_var, then use
#! /usr/bin/perl
use warnings;
use strict;
use vars;
sub create_glob_var { vars->import("\$$_[0]") }
BEGIN { create_glob_var "bah" }
$bah = "blah";
print $bah, "\n";
Either way, the output is
blah
I'm curious to know why you want to do it this way rather than declaring these variables with our. Yes, it may take a few iterations to catch them all, but these are short-term fixes anyway, right?
In general, you can use a variable as a variable name (see "Symbolic references" in perlref), but you really, really, really don't want to do that: enabling the strict 'refs' pragma disables this feature.
Rafael Garcia-Suarez showed great wisdom when he wrote, “I don't know what your original problem is, but I suggest to use a hash.”
See also:
Why it's stupid to 'use a variable as a variable name'
A More Direct Explanation of the Problem
What if I'm really careful?
Answer by Sinan Ünür is indeed the best. However, this picked my curiosity, so I did a bit of reading (perldoc perlmod)and learned about "package_name::" hash as a way to access the namespace of a package.
The following code adds a record to symbol table of main:: package:
use strict;
my $name = "blah";
my $var = "sss";
$main::{$name} = \$var;
print "$main::blah\n";
This prints "sss".
However, I had to add package name to print statement because "use strict" is still not fooled. I'll keep looking - use vars does not seem to work at the moment.