Hi Toby,

long mail ahead. Sorry.

Toby C via RT wrote:
Tue Feb 03 00:35:06 2009: Request 42986 was acted upon.
       Queue: PAR
     Subject: PAR-based modules use system XS modules over included modules

I have created a PAR file which contains my script, and the included
modules include an XS module.
However if I try to run the script, the XS module fails to load with
DynaLoader, as the system-installed .so file has been loaded, rather
than the one included with the PAR file.

Very strange. I did essentially exactly as you say and I could not reproduce the problem.

What happens when you try to run the .par with "par.pl test.par"?

What's the architectures and perl and PAR::Packer versions that were used to create the parl's you're using to execute the test.par? I guess you can find out like this:

mkdir tmp
cd tmp
cp `which parl` .

# save extract_embedded.pl from this mail to the directory
perl extract_embedded.pl parl .

grep archname Config.pm
# --> should print something like
# archname => 'i686-linux-thread-multi',

grep "version =>" Config.pm
# version => '5.10.0',

To find out the PAR (not PAR::Packer unfortunately) version, you can then do:
grep "VERSION" PAR.pm

With this information, you'll be able to verify or disprove the following guess of mine:

"The architectures or perl versions of your target machine's pArl and your development machine's pErl aren't really compatible."

Let me explain with some more detail:
- When you use pp to generate .par or ".exe" files, it puts a small script into the archive as "script/main.pl". That script is executed when you try to run a script from the archive via "parl" or "par.pl" and also for stand-alone executables. - The contents of main.pl are different depending on context. Specifically, if generating a stand-alone executable or using the -B option to pp, then main.pl will include some code that clears out the @INC before running the script. After all what you're executing is supposed to be stand-alone. - If you're using the -p option and not -B, i.e. creating a dependent .par file that expects a full perl installation, then it *naturally* doesn't clear @INC before running the user code.
- Your case is the second one.
- Since (I think) the perl installations (and specifically the pArl on the target machine and the pErl on your dev machine that runs pp) aren't entirely compatible, the XS.so in the .par will not be loaded. Instead, it will try to find a XS.so on the target system that's compatible to the target system's parl. - Such an XS.so is found, but after loading it, it turns out to be an incompatible VERSION!

Let's suppose this is the case. I still wouldn't exactly call this a mistake on your part. It's simply a darned complicated situation. It's also one of the reasons why I don't like the "parl FOO.par" use case or PAR::Packer. But still, I don't think it's a downright PAR bug either. It's the behaviour you're implicitly asking for by not bundling the whole perl environment (i.e. "please use what's already there").

I hope this clears up confusion and doesn't add to it :)

Best regards,
Steffen

P.S.: Food for thought and discussion: I just found out that adding -B to the "pp -p -o foo.par foo.pl" doesn't make "main.pl" clear @INC. I expected it would. We'll have to think about what the right behaviour is in that case. After all, it's bundling the core modules, so it should probably clear @INC before running, no?
#!/usr/bin/perl 

# code stolen from PAR script/parl.pl

use File::Spec;
use File::Basename;
use File::Path;
use strict;
use warnings;

@ARGV == 2 || die "usage: $0 executable directory_to_extract_into\n";
extract_embedded(@ARGV);

sub extract_embedded
{
    my ($exe, $xdir) = @_;

    open my $fh, '<', $exe or die qq[failed to open "$exe": $!];
    binmode $fh;

    my $buf;
    seek $fh, -8, 2;
    read $fh, $buf, 8;
    die qq[no PAR signature found in "$exe"] unless $buf eq "\nPAR.pm\n";

    seek $fh, -12, 2;
    read $fh, $buf, 4;
    seek $fh, -12 - unpack("N", $buf), 2;
    read $fh, $buf, 4;

    while ($buf eq "FILE") 
    {
        read $fh, $buf, 4;
        read $fh, $buf, unpack("N", $buf);

        my $fullname = $buf;
        print STDERR qq[FILE "$fullname"...];
        my $crc = ( $fullname =~ s|^([a-f\d]{8})/|| ) ? $1 : undef;
        my @path = split(/\//, $fullname);

        read $fh, $buf, 4;
        read $fh, $buf, unpack("N", $buf);

	my $file = File::Spec->catdir($xdir, @path);
	my $dir = dirname($file);
	mkpath($dir) unless -d $dir;

	open my $out, '>', $file or die qq[failed to open "$file": $!];
	binmode $out;
	print $out $buf;
	close $out;
	print STDERR qq[ extracted to $file\n];

        read $fh, $buf, 4;
    }

    close $fh;
}

Reply via email to