rmflow has asked for the wisdom of the Perl Monks concerning the following question:

Just found this tool for creating executables and liked it much, but I have some issues I cannot resolve.

For example, script named foo.pl
print "I'm $0\n";

is converted into executable foo.exe
When I run foo.pl it prints:
I'm foo.pl

When I run foo.exe it prints:
I'm -e

I.e. $0 variable has invalid value. Can anyone help me here?

Replies are listed 'Best First'.
Re: Cava Packager quick question
by marto (Cardinal) on Mar 25, 2010 at 14:22 UTC

    Maybe it relates to how cava works internally, from perlvar:

    If the program has been given to perl via the switches -e or -E , $0 will contain the string "-e" .

    Perhaps asking on the cava mailing list would provide clarification, I've never used it. Out of interest, have you given up on using pp?

      Thanks a lot for perlvar memo!

      As for pp - I use it also, but it is extremely slow in first run. And it leaves pre-cached files in %TEMP% dir (solution is -C option, but it would mean every run is extremely slow).

        There also is the newly released App::FatPacker, which tries to include all modules that a script uses in the main script file itself. This might speed up the process startup as there are fewer files to be extracted (and scanned by a virus scanner).

        Well I hope you find an answer to your cava problem, or at best a work around. From memory http://par.perl.org/ discusses some methods from creating a 'streamlined executable'.

Re: Cava Packager quick question
by SuicideJunkie (Vicar) on Mar 25, 2010 at 14:20 UTC

    I have noticed the same thing, as I tried to use it for the USAGE: response on invalid parameters. I didn't find a solution at the time, but it wasn't important to my script.

    Just in case this is an XY problem, what exactly do you want to use $0 for? There are always other ways to do things.

      $0 is used for Windows Registry entries to invoke my application from other applications. $0 variable allowed me to use my application without knowing what I'm actually running (.exe or .pl)

        Could you not set a registry entry with "perl script.pl" vs "script.exe" when you install your script? Another thing you might do is set the associations so that .pl files are opened with the perl interpreter (just say "script" and away you go). You could also place a batch file in the directory to launch whatever style you've installed (run startscript.bat).

        I'm not really sure how $0 helps you there however... you'd have to run your application to populate $0 in the first place, and at that point you're already running the code so you must have found it. Chicken vs Egg.

Re: Cava Packager quick question
by chocolateboy (Novice) on May 26, 2010 at 06:54 UTC
    There's code for determining $0 in Cava here
      NO there isn't
      BEGIN { use Cava::Pack; $0 = $Cava::Pack::EXEPATH; }
        That does indeed work. I guess the joke's on me for sticking to the documented APIs. I'm not quite sure why you (I'm assuming you're the developer, as EXEPATH doesn't appear in any of Cava's Perl modules, and everything else is closed source), would choose to unveil this here (and only here) rather than, say:

        • on the website
        • in the newsgroup
        • in the PODs

Re: Cava Packager quick question
by Anonymous Monk on Mar 26, 2010 at 04:57 UTC
    RTFM
    Common Problems Cava Packager works well in most situations but there are one or two c +ommon situations that may cause packaged scripts to behave differentl +y. Checking for caller If you check caller in your scripts you may not get what you expect. C +ava Packager runs your script with the equivalent of: do 'yourscript.pl'; This means that, for example, code such as: if(caller) { will no longer work as you might expect because caller will always con +tain details from the enclosing 'do'. INIT blocks According to the perldocs, modules that contain INIT blocks will behav +e differently when called from within an 'eval' or 'do'. We have had +no reports of any issues arising from this fact, but you should be aw +are of it if you use INIT blocks. Cava Packager Copyright © 2006-2008 Mark Dootson
      Am I missing something? I don't see anything that helps get the name of the executable. (Or says anything about $0.)
        It explains how the script is run. I'm sure other parts of the docs explain other things
        perldoc -m Cava::Pack ###################################################################### +####### ## Name: Cava::Pack.pm ## Author: Mark Dootson ## Created: 01/02/2007 ## Copyright: (c) 2007 Mark Dootson ## Licence: This program is free software; you can redistribute it + and/or ## modify it under the same terms as Perl itself ###################################################################### +####### package Cava::Pack; require DynaLoader; use vars qw(@ISA $VERSION $RESPATH $BINPATH $TMPPATH $__cvpk_info); @ISA = qw(DynaLoader); $VERSION = '1.1.0.8'; bootstrap Cava::Pack $VERSION; use strict; $BINPATH = GetFullPathName($0); $BINPATH = CodePath($BINPATH); { my @parts = split(/[\/\\]/, $BINPATH); pop(@parts); $BINPATH = join('/', @parts); } $RESPATH = $BINPATH; { my @parts = split(/[\/\\]/, $RESPATH); pop(@parts); $RESPATH = join('/', @parts) . '/res'; } $TMPPATH = ''; #--------------------------------------------------------- # set default product Info #--------------------------------------------------------- # Note - defaults when packaged are set via Cava Packager { $__cvpk_info = { ProductName => 'Product Name', ProductVersion => '0.0.0.0', Vendor => 'Vendor Name', Copyright => 'Copyright Notice', Trademarks => 'Trademarks', Comments => 'Comments', FileDescription => 'Perl Script', FileInternalName => 'default.pl', FileVersion => '0.0.0.0', FileOriginalName => 'default.exe', }; } #--------------------------------------------------------- sub __cvpk_purge_dir { my $dirpath = shift; my $rm = shift || 0; $dirpath = CodePath($dirpath); return 0 if(! $dirpath); my @tempfiles = (); eval { opendir(DIR, $dirpath) or return 0; @tempfiles = readdir(DIR); closedir DIR; }; foreach my $tmp (@tempfiles) { next if(($tmp eq '.') || ($tmp eq '..')); my $newtmp = qq($dirpath/$tmp); if(-l $newtmp) { eval { unlink CodePath($newtmp); }; } elsif(-d $newtmp) { __cvpk_purge_dir($newtmp, 1); } elsif(-f $newtmp) { eval { unlink CodePath($newtmp); }; } } eval { if($rm) { rmdir $dirpath; } }; } sub CAVA_FOLDER_PERSONAL () { 0x0005 } sub CAVA_FOLDER_LOCAL_APPDATA () { 0x001C } sub CAVA_FOLDER_APPDATA () { 0x001A } sub CAVA_FOLDER_COMMON_APPDATA () { 0x0023 } sub Packaged () { 0 } sub Resource { my $filename = shift; return qq($RESPATH/$filename); } sub CodePath { my $path = shift; # return a perl happy path. # forward slash delimiters # individual directory/ file names converted # to short form if they contain spaces # NOTE - path must exist; my $shortpathstr = GetShortPathName($path); my $longpathstr = GetLongPathName($path); $shortpathstr =~ s/\\/\//g; $longpathstr =~ s/\\/\//g; my @shortnames = split(/\//, $shortpathstr); my @longnames = split(/\//, $longpathstr); my $limit = (scalar @shortnames); my $index = 0; my @outpath = (); while($index < $limit) { if($longnames[$index] =~ /\s/) { push(@outpath, $shortnames[$index]); } else { push(@outpath, $longnames[$index]); } $index ++; } my $newpath = join('/', @outpath); if($newpath =~ /\w/) { return $newpath; } else { return undef; } } sub ShortPath { my $path = shift; $path = GetShortPathName($path); $path =~ s/\\/\//g; return $path; } sub DisplayPath { my $path = shift; $path =~ s/\//\\/g; $path = GetLongPathName($path); return $path; } sub GetUserAppDataDir { __cvpk_get_shell_folder( CAVA_FOLDER_LOCAL_APPDATA() ); } sub GetUserDocumentDir { __cvpk_get_shell_folder( CAVA_FOLDER_PERSONAL() ); } sub GetCommonAppDataDir { __cvpk_get_shell_folder( CAVA_FOLDER_COMMON_APPDATA() ); } sub GetTempDir { if(!$TMPPATH){ # create temp path my $temproot = CodePath($ENV{TMP}); if(!-w $temproot) { $temproot = CodePath($ENV{TEMP}); } if(!-w $temproot) { $temproot = CodePath($ENV{USERPROFILE}); } + my $chars = __cvpk_gen_randomchars(11); my $tmpstr = 'cvpk-' . $chars; my $temppath = qq($temproot/$tmpstr); mkdir($temppath, 0777); $TMPPATH = $temppath; } return $TMPPATH; } sub GetTempFile { my $tempfile = ''; while($tempfile eq '') { my $tmp = GetTempDir() . '/' . __cvpk_gen_randomchars(12) . '. +tmp'; if(!-e $tmp) { open my $tfh, ">", $tmp; close($tfh); $tempfile = $tmp; } } return $tempfile; } sub __cvpk_get_shell_folder { my $type = shift; my $path = GetFolderPath($type,1); CodePath($path); } # all 'Set' subs are noops when packaged with Cava Packager sub SetResourcePath { my $path = shift; $path = GetFullPathName($path); $RESPATH = CodePath($path); } sub SetInfoProductName { $__cvpk_info->{ProductName} = shift; } sub SetInfoProductVersion { $__cvpk_info->{ProductVersion} = shift; } sub SetInfoVendor { $__cvpk_info->{Vendor} = shift; } sub SetInfoCopyright { $__cvpk_info->{Copyright} = shift; } sub SetInfoTrademarks { $__cvpk_info->{Trademarks} = shift; } sub SetInfoComments { $__cvpk_info->{Comments} = shift; } sub SetInfoFileDescription { $__cvpk_info->{FileDescription} = shift; } sub SetInfoFileInternalName { $__cvpk_info->{FileInternalName} = shift; } sub SetInfoFileVersion { $__cvpk_info->{FileVersion} = shift; } sub SetInfoFileOriginalName { $__cvpk_info->{FileOriginalName} = shift; } sub GetInfoProductName { return $__cvpk_info->{ProductName}; } sub GetInfoProductVersion { return $__cvpk_info->{ProductVersion}; } sub GetInfoVendor { return $__cvpk_info->{Vendor}; } sub GetInfoCopyright { return $__cvpk_info->{Copyright}; } sub GetInfoTrademarks { return $__cvpk_info->{Trademarks}; } sub GetInfoComments { return $__cvpk_info->{Comments}; } sub GetInfoFileDescription { return $__cvpk_info->{FileDescription}; } sub GetInfoFileInternalName { return $__cvpk_info->{FileInternalName}; } sub GetInfoFileVersion { return $__cvpk_info->{FileVersion}; } sub GetInfoFileOriginalName { return $__cvpk_info->{FileOriginalName}; } sub __cvpk_gen_randomchars { my $numchars = shift; my @vals = qw(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z +a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 + 9); my $buffer = ''; for (my $i = 1; $i <= $numchars; $i++) { my $index = int(rand(scalar @vals)); $buffer .= $vals[$index]; } return $buffer; } END { # do cleanup if we didn't clean up; eval { if($TMPPATH) { __cvpk_purge_dir($TMPPATH,1); } }; } 1; __END__