Undefined subroutine &Scalar::Util::refaddr called at overload.pm
line92.
In an attempt to troubleshoot this, I added:
use Scalar::Util qw(refaddr);
to the script.
The script still runs fine when I run script.pl through perl, but now,
when I package the exe, and run it i get:
"refaddr" is not exported by the Scalar::Util module
This is somewhat confusing, as obviously Scalar::Util successfully
exportts refaddr when run as a perl script, but as the packaged exe, it
does not.
In Scalar/Util.pm:
refaddr is listed in @EXPORT_OK
however, sub refaddr { ... } is in a block that is only eval'd if a XS
import fails. Somehow it appears that in the pp packed version, the XS
doesn't load, but that block is not evaled either, as the refaddr
function is not exportable.
I guess I can fix it by hacking the XS load out of Scalar/Util.pm, and
forcing the sub refaddr { ... } perl function to be eval'd, but I was
sort of hoping someone else had a cleaner way to do this.
Thanks.
--
***********************************
* Alex Laslavic
* Linux Engineer
* WorldTravel BTI
* x49511
* gpg/pgp key at
* http://keys.jumpbox.net
***********************************
> The script still runs fine when I run script.pl through perl, but now,
> when I package the exe, and run it i get:
> "refaddr" is not exported by the Scalar::Util module
My understanding is that the error message is simply telling you that
"refaddr" is not listed in either @EXPORT or @EXPORT_OK.
I mean - you can have a Foo.pm that looks like:
package Foo;
use strict;
require Exporter;
our $VERSION = 0.01;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(garbage);
1;
And you can load that module from a script as:
use Foo qw(garbage);
and the fact that garbage() doesn't even exist matters not. (And you can
then build that script inot an executable and run it without any trouble -
at least on 0.90 you can.)
Could it be that the exe is picking up some version of Scalar::Util that
does not, in fact, export "refaddr". I would check that both the script and
the executable are getting hold of the same version of Scalar::Util by:
print $Scalar::Util::VERSION, "\n";
Cheers,
Rob
Have you tried the -M switch, which will explicitly name the module?
As in
pp -o file.exe -M Scalar::Util script.pl'
Good luck
Can you verify that Scalar::Util was correctly packed by running
unzip -l file.exe
You should see something like
...
3370 03-30-06 14:12 lib/Scalar/Util.pm
...
28770 11-02-05 09:49 lib/auto/List/Util/Util.dll
(that's right: List/Util/Util.dll is where the XS version of refaddr
comes from)
Note that I couldn't reproduce your problem with the following oneliner
(ActiveState 5.8.7 build 815, PAR 0.92, Scalar::Util 1.14)
pp -o ref.exe -e "use Scalar::Util qw/refaddr/; my $x; my $a=refaddr
\$x; print qq[refaddr=$a\n];"
Cheers, Roderich
>
> This is somewhat confusing, as obviously Scalar::Util successfully
> exportts refaddr when run as a perl script, but as the
> packaged exe, it
> does not.
>
> In Scalar/Util.pm:
> refaddr is listed in @EXPORT_OK
> however, sub refaddr { ... } is in a block that is only eval'd if a XS
> import fails. Somehow it appears that in the pp packed
> version, the XS
> doesn't load, but that block is not evaled either, as the refaddr
> function is not exportable.
>
> I guess I can fix it by hacking the XS load out of Scalar/Util.pm, and
> forcing the sub refaddr { ... } perl function to be eval'd, but I was
> sort of hoping someone else had a cleaner way to do this.
>
>
> Thanks.
>
>
>
Following up my previous mail:
Did you build pp.exe from the same version of perl and Scalar::Util
that is now on the machine you are packing script.pl?
(I just realized that pp.exe contains "built-in" versions of
Scalar/Util.pm and List/Util/Util.dll that might be older
than the ones now deployed; these are probably preferred at runtime
over other versions that may be present in the zip archive file.exe).
Cheers, Roderich
Util.pm and Util.dll are the same version, both for the perl running on
my system, and for the files packed into the exe.
pp.exe is from ActiveState's package manager. I suppose I can build it
by hand, and see if I get anything different, however, the correct
version of Scalar::Util is packed into the exe.
Actually there are TWO versions of Scalar::Util etc in
the executable created by pp from my oneliner:
- one is in the zip archive at the end of the executable;
this one you can list/extract by running e.g. unzip on
the excutable; this one is from the machine where
you ran pp
- the other is in the data section of the executable;
you can see it with "strings file.exe";
it is copied verbatim from parl.exe where it got included
when your PAR package was built; it's part of the
pp'ed executables' bootstrap, because some perl modules
are already needed extracted before PAR can get to
the modules in the zip archive
So there's a potential mismatch, but that's just a wild guess.
Does the oneliner from my previous email have the same problem as your
script?
Cheers, Roderich
Yup. It sure does.
'refaddr' is not exported by the Scalar::Util module.
I guess I'm going to try to build the PAR bundle from source, and delete
the version from activestate. Hopefully that will get the correct
version of Scalar::Util packed into the exe.
You are right on. The packed exe has version 1.07, and the script is
written, and using 1.18. Now, if only I can get it to use 1.18....
use Scalar::Util 1.18 qw/refaddr/ doesn't seem to work....
Oddly, when I unzip the exe that I have created with pp, the 1.18
version is actuall in the LIB/SCALAR/ directory, but it doesn't seem to
get loaded at runtime, even with:
use Scalar::Util 1.18
Any ideas?
ls
>
> Cheers, Roderich
For the sake of future google searchers, here is how I worked around
this.
Scalar::Util 1.07 is currently packaged into pp.exe, as it is shipped
from ActiveState PPM. You could probably recompile PAR, and pp.exe, but
I don't have Visual C++ handy, so I got around it another way.
The problem is that 1.07 was already loaded into %INC by the time my
script was executed, and I couldn't then load 1.18. My solution:
delete $INC{'Scalar/Util.pm'};
eval 'use Scalar::Util 1.18 qw(refaddr);';
This removes the 1.07 Scalar::Util, and then allows me to load 1.18 at
runtime. Not pretty, but it works.
The latter only checks that Scalar::Util should have at least
version 1.18 or die otherwise - it doesn't mean try another
Scalar::Util down the road whether it may satisfy the version
constraint.
The real problem is the way pp generates executables
(read on at your own risk :)
The basic idea is: just create a PAR archive and make it into
an executable. But in order to get to the perl modules
in the PAR we already must have PAR.pm loaded. And PAR.pm
requires other modules, e.g. Archive::Zip which require
others, e.g. Scalar::Util. So the PAR distribution
creates a standalone, statically linked, special purpose
version of the perl executable: that's basically what
parl.exe is. Before the perl interpreter in this special-built
perl variant is start, some things are done from C functions,
e.g. setup the cache directory, copy the perl shared library
into do (from C arrays contained in parl.exe) and set $ENV{PART_TEMP}
to it. Then the perl interpreter gets started with a little bootstrap
Perl code that is hand-crafted not to use any modules at all.
It extracts the modules absolutely necessary to access a PAR
archive by pure-perl means form the pp'ed executable itself
(this data is not in the PAR archive part, it has been simply
appended to the executable with special markers and headers
taht you can see if you run "strings" on the executable). Once
this modules have been extracted to the cache area, the
bootstrap code "require"s them. Now the code is able to
load the rest of the modules from the PAR archive (that has also
been appended to the executable and which is accessible by
running "unzip" on the executable) as if you had said
"perl -MPAR -Ifoo.exe ...".
The consequence is that building a PAR distribution captures
the state of your perl distribution (the version of perl itself
and that of several core and non-core modules) at the time of
the build (essentially this is frozen into parl.exe). If you install
another
version of perl or upgrade core modules (without rebuilding PAR),
pp'ed executables afterwards might behave differently than the original
scripts, because the use the captured versions. Sometimes these
differences will already show on the build machine, at other times
they only manifest themselves in another environment.
Perhaps the PAR build process should remember checksums of all
the stuff that goes into parl.exe and recheck against the
actually installed versions at pp'ing time and at least warn you
to better rebuild your PAR.
Cheers, Roderich