Hello List, I am maintaining a perl/Tk database app and use PAR::Packer to create binaries. Works perfect on Linux/ MacOS /Windows - thanks for a great tool. There are a lot of dependencies in my app therefore the packing takes some minutes. Now I was making up my mind about the possibility to add a dependencies cache - most of the time my dependencies do not change - and just tried it. It's a quick hack: uses Storable to store/retrieve state inside the pack_manifest_hash method. However it works and I'd like to share it here, maybe as a feature suggestion rather than a patch... It speeds packing up from minutes to seconds in my case. Btw sorry: Diff is against $VERSION = '0.982' I didn't check before I started...
Cheers, Christoph
--- C:\Dokumente und Einstellungen\chris\Desktop\oper_wc\PAR\Packer-ori.pm Di Jul 29 17:36:44 2008 +++ C:\Dokumente und Einstellungen\chris\Desktop\oper_wc\PAR\Packer.pm Fr Jun 26 01:22:32 2009 @@ -33,6 +33,7 @@ use File::Spec (); use File::Temp (); use Module::ScanDeps (); +use Storable; use PAR (); use PAR::Filter (); @@ -69,6 +70,8 @@ 'vv|verbose2', => 'Verbosity level 2', 'vvv|verbose3', => 'Verbosity level 3', 'z|compress:i' => 'Compression level', + 'D|savedeps:s' => 'Save detected dependencies to a file', + 'U|usedeps:s' => 'Read dependencies from a file', }; my $ValidOptions = {}; @@ -453,7 +456,7 @@ my $opt = $self->{options}; my $par_file = $self->get_par_file(); - + $self->_add_pack_manifest(); $self->_add_add_manifest(); $self->_make_manifest(); @@ -470,7 +473,6 @@ sub _write_zip { my ($self) = @_; - my $old_member = $self->{pack_attrib}{old_member}; my $oldsize = $self->{pack_attrib}{old_size}; my $par_file = $self->{par_file}; @@ -538,7 +540,6 @@ sub _make_manifest { my ($self) = @_; - my $full_manifest = $self->{full_manifest}; my $opt = $self->{options}; @@ -665,100 +666,127 @@ my $par_file = $self->{par_file}; my (@modules, @data, @exclude); - foreach my $name (@{ $opt->{M} || [] }) { - $self->_name2moddata($name, \...@modules, \...@data); - } + my %map; + my %text; + + if ($opt->{usedeps}) { + my $file = $opt->{usedeps}; + my $stored = retrieve($file) + or die "Couldn't retrieve from file[$file]\n"; + my ($stored_obj,$stored_data) = @$stored; + my $pack_attrib = delete $stored_obj->{pack_attrib}; + # compare deeply here and croak if settings differ? + for my $slot (qw/text + map + shared_libs + /) { + $self->{pack_attrib}{$slot} = $pack_attrib->{$slot}; + } + %map = %{$pack_attrib->{map}}; + %text = %{$pack_attrib->{text}}; + @SharedLibs = @{$pack_attrib->{shared_libs}}; + @data = @$stored_data; + } else { + + foreach my $name (@{ $opt->{M} || [] }) { + $self->_name2moddata($name, \...@modules, \...@data); + } - # Skip either - # a) all files from a .par file or - # b) A module - foreach my $name ('PAR', @{ $opt->{X} || [] }) { - if (-f $name and my $dep_zip = Archive::Zip->new($name)) { - for ($dep_zip->memberNames()) { - next if ( /MANIFEST/ or /META.yml/ or /^script\// ); - $dep_zip_files{$_} ||= $name; + # Skip either + # a) all files from a .par file or + # b) A module + foreach my $name ('PAR', @{ $opt->{X} || [] }) { + if (-f $name and my $dep_zip = Archive::Zip->new($name)) { + for ($dep_zip->memberNames()) { + next if ( /MANIFEST/ or /META.yml/ or /^script\// ); + $dep_zip_files{$_} ||= $name; + } + } else { + $self->_name2moddata($name, \...@exclude, \...@exclude); } } - else { - $self->_name2moddata($name, \...@exclude, \...@exclude); - } - } - my %map; + + unshift(@INC, @{ $opt->{I} || [] }); + unshift(@SharedLibs, + map $self->_find_shlib($_, $sn), @{ $opt->{l} || [] }); - unshift(@INC, @{ $opt->{I} || [] }); - unshift(@SharedLibs, map $self->_find_shlib($_, $sn), @{ $opt->{l} || [] }); + my $inc_find = $self->_obj_function($fe, '_find_in_inc'); - my $inc_find = $self->_obj_function($fe, '_find_in_inc'); + my %skip = map { $_, 1 } map &$inc_find($_), @exclude; + if ($^O eq 'MSWin32') { + %skip = (%skip, map { s{\\}{/}g; lc($_), 1 } @SharedLibs); + } else { + %skip = (%skip, map { $_, 1 } @SharedLibs); + } - my %skip = map { $_, 1 } map &$inc_find($_), @exclude; - if ($^O eq 'MSWin32') { - %skip = (%skip, map { s{\\}{/}g; lc($_), 1 } @SharedLibs); - } - else { - %skip = (%skip, map { $_, 1 } @SharedLibs); - } + my $add_deps = $self->_obj_function($fe, 'add_deps'); - my $add_deps = $self->_obj_function($fe, 'add_deps'); - - my @files; # files to scan - # Apply %Preload to the -M'd modules and add them to the list of - # files to scan - foreach my $module (@modules) { - my $file = &$inc_find($module); - push @files, $file; + my @files; # files to scan + # Apply %Preload to the -M'd modules and add them to the list of + # files to scan + foreach my $module (@modules) { + my $file = &$inc_find($module); + push @files, $file; - my $preload = Module::ScanDeps::_get_preload($module) or next; + my $preload = Module::ScanDeps::_get_preload($module) or next; - $add_deps->( - used_by => $file, - rv => \%map, - modules => $preload, - skip => \%skip, -# warn_missing => $args->{warn_missing}, - ); - push @files, map {&$inc_find($_)} @$preload; - } - push @files, @$input; + $add_deps->( + used_by => $file, + rv => \%map, + modules => $preload, + skip => \%skip, + # warn_missing => $args->{warn_missing}, + ); + push @files, map {&$inc_find($_)} @$preload; + } + push @files, @$input; - # Search for scannable code in all -I'd paths - push @Module::ScanDeps::IncludeLibs, @{$opt->{I}} if $opt->{I}; + # Search for scannable code in all -I'd paths + push @Module::ScanDeps::IncludeLibs, @{$opt->{I}} if $opt->{I}; - my $scan_dispatch = - $opt->{n} - ? $self->_obj_function($fe, 'scan_deps_runtime') - : $self->_obj_function($fe, 'scan_deps'); + my $scan_dispatch = + $opt->{n} + ? $self->_obj_function($fe, 'scan_deps_runtime') + : $self->_obj_function($fe, 'scan_deps'); - $scan_dispatch->( - rv => \%map, - files => \...@files, - execute => $opt->{x}, - compile => $opt->{c}, - skip => \%skip, - ($opt->{n}) ? () : ( - recurse => 1, - first => 1, - ), - ); + $scan_dispatch->( + rv => \%map, + files => \...@files, + execute => $opt->{x}, + compile => $opt->{c}, + skip => \%skip, + ($opt->{n}) ? () : ( + recurse => 1, + first => 1, + ), + ); - %skip = map { $_, 1 } map &$inc_find($_), @exclude; - %skip = (%skip, map { $_, 1 } @SharedLibs); + %skip = map { $_, 1 } map &$inc_find($_), @exclude; + %skip = (%skip, map { $_, 1 } @SharedLibs); - &$add_deps( - rv => \%map, - modules => \...@modules, - skip => \%skip, - ); + &$add_deps( + rv => \%map, + modules => \...@modules, + skip => \%skip, + ); - my %text; - $text{$_} = ($map{$_}{type} =~ /^(?:module|autoload)$/) for keys %map; - $map{$_} = $map{$_}{file} for keys %map; + $text{$_} = ($map{$_}{type} =~ /^(?:module|autoload)$/) for keys %map; + $map{$_} = $map{$_}{file} for keys %map; - $self->{pack_attrib}{text} = \%text; - $self->{pack_attrib}{map} = \%map; - $self->{pack_attrib}{shared_libs} = \...@sharedlibs; + $self->{pack_attrib}{text} = \%text; + $self->{pack_attrib}{map} = \%map; + $self->{pack_attrib}{shared_libs} = \...@sharedlibs; + #print Dumper \%text, \%map, \...@sharedlibs, \%skip; + if ($opt->{savedeps}) { + my $file = $opt->{savedeps}; + store([$self,\...@data], $file) + or die "Can't store $self in file [$file\\n"; + } + } + my $size = 0; my $old_member;