m.nooning wrote:
Malcolm Nooning wrote:
Hello,
How can I identify the bundled perl binary from within a pp created
executable? Perl will NOT be installed on the end user's machine.
Specifically, I would like to do something like this:
Win32::Process::Create($ProcessObj,
"full_path_to_the_by now_unwrapped_perl.exe",
"perl.exe bundled_perl_file.pl",
0,
NORMAL_PRIORITY_CLASS,
".")|| die ErrorReport();
I have need for one process to watch another and kill it if there is a
problem. Since I use Tk, which is not thread safe, I cannot use the
Windows fork (Perl 5.8.8 + fork + Tk worked on Windows XP but not on
Windows 2000).
Another solution would be to create a separate pp'd .exe to be
executed as the Win32::Process::Create invoked process. However, the
extra time taken up in the initial unwrapping/unbundling, etcetera,
would seem unpalatable. That is why I am hoping for a scheme wherein
I could use the by-then already unbundled perl.exe.
A quick search reveals that there is no perl.exe anywhere under the
par-malcolm directory. My next question is then ... how could my end
goal be reached?
Thanks
------------------------------
I would like to continue this request for assistance, as I have made
some progress. I think that if I could get this to work it would open
up a lot of areas for PAR/pp.
I would like to have two emails, this one and the next. This first one
outlines how the end goal can be reached by having one .exe invoke
another. Since it works, albeit more slowly than desired, I will just
post this and forget about it.
My next email will show where I am stuck trying to have a faster
implementation.
For those that might get along fine with one exe invoking another, a
"test_minus_a_invoked.exe" can be created, along with an "invoked.exe",
wherein invoked.exe is invoked within test_minus_a_invoked.exe. The
command lines and the reasoning are shown below. This assumes that the
working directory is c:\aaa.
pp -o invoked.exe invoked.pl # Nothing new here
pp -o test_invoked_from_cache.exe -a
"c:/perl/bin/perl.exe;inc/../../perl.exe" -a
"c:/aaa/invoked.exe;invoked.exe" test_invoked_from_cache.pl
Above I am taking C:/perl/bin/perl.exe and putting it into the top level
directory where the perl.dll is normally placed. I do not know if it
is really necessary, but that is what I did.
The business of
"c:/perl/bin/perl.exe;inc/../../perl.exe" is there instead of, say,
"c:/perl/bin/perl.exe;/perl.exe"
because just using "/perl.exe" did not seem to work, so I think I had to
trick pp a little to get it into the upper level cache directory.
The
-a "c:/aaa/invoked.exe;invoked.exe"
puts invoked.exe into .../cache-xxx/inc/invoked.exe.
From here, assuming I have the fully qualified path name to the cache
directory from within test_invoked_from_cache, I can do this within
test_minus_a_invoked.pl
my $fqpn_invoked = File::Spec->catfile( $par_base,
"inc",
"invoked.exe",
);
if (system(" \"$fqpn_invoked\" ")) {
die("100 OUCH\n");
} else {
print("105 Success \n");
}
You may well ask, just how can we know the cache directory? Here is the
way I did it. Does anyone know an easier way?
------------- paste sub
sub find_par_temp_base {
my ($debug) = @_;
#################################################################
# Originally taken from par.pl:_set_par_temp. The lines
# containing $Config{_delim} were replaced by
# File::Spec->catdir(whatever, whatever);
#################################################################
my $path = "";
my $par_temp = "";
my $progname = "";
my $username = "";
my $stmpdir = "";
my $mtime = "";
my $ctx = "";
print("msg210:\n") if $debug;
if ($ENV{PAR_TEMP} and $ENV{PAR_TEMP} =~ /(.+)/) {
$par_temp = $1;
print("msg215: Returning $par_temp\n") if $debug;
return ($par_temp);
}
foreach $path (
(map $ENV{$_}, qw( TMPDIR TEMP TMP )),
qw( C:\\TEMP /tmp . )
) {
next unless $path and -d $path and -w $path;
$username = defined(&Win32::LoginName)
? &Win32::LoginName()
: $ENV{USERNAME} || $ENV{USER} || 'SYSTEM';
$stmpdir = File::Spec->catdir($path, "par-$username");
last;
}
print ("msg270: stmpdir is $stmpdir\n") if $debug;
return ($stmpdir);
}
-------------- end paste sub
and then do:
my $par_base = find_par_temp_base(0);
So there it is. The above was just a proof-of-concept so that one can
have a system command that utilized the already bundled up perl.
But what if you had a parent/child application? The code below also
worked. I pasted it just after the already stated "system" command.
-------------paste this also worked
my $ProcessObj;
my $exitcode = "";
Win32::Process::Create($ProcessObj,
$fqpn_invoked,
"invoked.exe",
0,
NORMAL_PRIORITY_CLASS,
".")|| die ("Phooey:$!:\n");
sleep(2);
print("This is the parent just after waiting for the child\n");
$ProcessObj->Kill($exitcode);
--------------end paste this also worked
--------------------------------------------
>so that one can have a system command that utilized the already
bundled up perl.
I was getting a little ahead of myself there. The prior email was
working with pp'd exe files, one via "system", and the other via
Win32::Process::Create.
Now I would like to reach the goal of using a system command that
utilized the already bundled up perl. If that could be done, then
coming up with a parent/child scheme with Win32::Process::Create would
easily follow.
I am really just looking for advice about things I might be able to try.
I intend here to present something that, seems to me, should have
worked. I intend to show some code snippets to bring out the reasoning,
and then give the pp command, then show the errant results, and then
show the actual proof-of-concept test files used.
As I stated, it looks (to me) like it should have worked. Again, if
this problem can be solved I think it will open up par/pp to a new class
of applications. Namely, to those applications wherein a parent needs
to create and watch a child while at the same time using a non-thread
safe gui tool such as Tk.
Okay, here we go.
In this case, the buildup of the system command would look something
like this:
---------paste proposed parent code
my $par_base = find_par_temp_base(0); # As before
# My pp command line will put the perl.exe here:
my $fqpn_perl = File::Spec->catfile($par_base, "perl.exe");
# My pp command line will put the child .pl file here:
my $fqpn_invoked = File::Spec->catfile( $par_base,
"inc",
"invoked_as_pl.pl",
);
# The child process will need all the libraries of the already
# unbundled perl so I will have to give it the parent's @INC path.
# The invoked_as_pl.pl file will get the inc path in $ARGV[0];
my $inc = join(" ", @INC);
if (system(" \"$fqpn_perl\" \"$fqpn_invoked\" \" . $inc . \" ")) {
------------end paste parent code
The invocation command would look like this:
pp -o test_minus_a_invoked.exe -a
"c:/perl/bin/perl.exe;inc/../../perl.exe" -a
"c:/aaa/invoked_as_pl.pl;invoked_as_pl.pl" test_minus_a_invoked.pl
Unfortunately, it does not work. I get an error indicating that Tk.pm
(used in invoked_as_pl.pl) cannot be found, as shown below. But the
Tk.pm file certainly is in the path. So ... what is wrong?
-------------paste results
C:\aaa>test_minus_a_invoked.exe
Parental path is
C:\DOCUME~1\malcolm\LOCALS~1\Temp\par-malcolm\cache-844032a64d7cff289f1a30007fccb5d9d6748757\inc\lib
C:\DOCUME~1\malcolm\LOCALS~1\Temp\par-malcolm\cache-844032a64d7cff289f1a30007fccb5d9d6748757\inc
CODE(0xef4644) CODE(0xef477c)
Child says ARGV 0 is
C:\DOCUME~1\malcolm\LOCALS~1\Temp\par-malcolm\cache-844032a64d7cff289f1a30007fccb5d9d6748757\inc\lib
C:\DOCUME~1\malcolm\LOCALS~1\Temp\par-malcolm\cache-844032a64d7cff289f1a30007fccb5d9d6748757\inc
CODE(0xef4644) CODE(0xef477c)
Can't locate Tk.pm in @INC (@INC contains: .
C:\DOCUME~1\malcolm\LOCALS~1\Temp\par-malcolm\cache-844032a64d7cff289f1a30007fccb5d9d6748757\inc\lib
C:\DOCUME~1\malcolm\LOCALS~1\Temp\par-malcolm\cache-844032a64d7cff289f1a3
0007fccb5d9d6748757\inc CODE(0xef4644) CODE(0xef477c) ) at
C:\DOCUME~1\malcolm\LOCALS~1\Temp\par-malcolm\cache-844032a64d7cff289f1a30007fccb5d9d6748757\inc\invoked_as_pl.pl
line 13.
BEGIN failed--compilation aborted at
C:\DOCUME~1\malcolm\LOCALS~1\Temp\par-malcolm\cache-844032a64d7cff289f1a30007fccb5d9d6748757\inc\invoked_as_pl.pl
line 13.
100 Cannot
----------------end paste results
--------------paste location of Tk.pm
Directory of
C:\DOCUME~1\malcolm\LOCALS~1\Temp\par-malcolm\cache-844032a64d7cff289f1a30007fccb5d9d6748757\inc\lib
01/22/2007 07:22 PM 19,053 Tk.pm
---------------end paste location of Tk.pm
As you can see above, Tk.pm is in the path that the invoked_as_pl.pl
file knows about.
Here is the test_minus_a_invoked.pl
--------------paste test_minus_a_invoked.pl
#!/usr/bin/perl -w
#File test_minus_a_invoked.pl
# Works when doing this:
# pp -o test_minus_a_invoked.exe -a \
# "c:/perl/bin/perl.exe;inc/../../perl.exe" \
# -a "c:/aaa/invoked_as_pl.pl;invoked_as_pl.pl"
test_minus_a_invoked.pl
#
#########################################################################
use PAR;
use File::Spec;
use Tk;
use Cwd;
use Win32::Process;
use Win32;
####################
sub okay_response {
my ($we_top) = @_;
$we_top->destroy;
}
###################
sub pop_up_a_message {
my ( $message, ) = @_;
my $okay_button;
my $we_top = new MainWindow;
$we_top->Label
(
-text => $message . "\n",
-justify => 'left',
)->pack(-padx =>10);
#.....................................................................
$okay_button =
$we_top->Button( -text => "Okay",
-command => [ \&okay_response,
$we_top,
]
)->pack(-ipadx =>10);
#.....................................................................
#########
MainLoop;
#########
}
###################
########################################################################
sub find_par_temp_base {
my ($debug) = @_;
#################################################################
# Originally taken from par.pl:_set_par_temp. The lines
# containing $Config{_delim} were replaced by
# File::Spec->catdir(whatever, whatever);
#################################################################
my $path = "";
my $par_temp = "";
my $progname = "";
my $username = "";
my $stmpdir = "";
my $mtime = "";
my $ctx = "";
print("msg210:\n") if $debug;
if ($ENV{PAR_TEMP} and $ENV{PAR_TEMP} =~ /(.+)/) {
$par_temp = $1;
print("msg215: Returning $par_temp\n") if $debug;
return ($par_temp);
}
foreach $path (
(map $ENV{$_}, qw( TMPDIR TEMP TMP )),
qw( C:\\TEMP /tmp . )
) {
next unless $path and -d $path and -w $path;
$username = defined(&Win32::LoginName)
? &Win32::LoginName()
: $ENV{USERNAME} || $ENV{USER} || 'SYSTEM';
$stmpdir = File::Spec->catdir($path, "par-$username");
last;
}
print ("msg270: stmpdir is $stmpdir\n") if $debug;
return ($stmpdir);
}
########################################################################
pop_up_a_message ("Hello from parent\n");
my $par_base = find_par_temp_base(0);
my $fqpn_perl = File::Spec->catfile($par_base, "perl.exe");
my $fqpn_invoked = File::Spec->catfile( $par_base,
"inc",
"invoked_as_pl.pl",
);
my $inc = join(" ", @INC);
print ("Parental path is \n");
print ("@INC\n");
if (system(" \"$fqpn_perl\" \"$fqpn_invoked\" \" $inc \" ")) {
die("100 Cannot\n");
} else {
print("105 Success with system \"$fqpn_perl\" \"$fqpn_invoked\" . \"
. $inc . \"\n");
}
--------------end paste test_minus_a_invoked.pl
and, lastly,
----------------paste invoked_as_pl.pl
#File: invoked_as_pl.pl
BEGIN {
push (@INC, ($ARGV[0]));
print "Child says ARGV 0 is $ARGV[0]\n";
}
if (@ARGV == 0 ) {
print("520: You forgot the parameter for invoked_as_pl.pl\n");
exit(1);
}
use Tk;
####################
sub okay_response {
my ($we_top) = @_;
$we_top->destroy;
}
###################
sub pop_up_a_message {
my ( $message, ) = @_;
my $okay_button;
my $we_top = new MainWindow;
$we_top->Label
(
-text => $message . "\n",
-justify => 'left',
)->pack(-padx =>10);
#.....................................................................
$okay_button =
$we_top->Button( -text => "Okay",
-command => [ \&okay_response,
$we_top,
]
)->pack(-ipadx =>10);
#.....................................................................
#########
MainLoop;
#########
}
###################
pop_up_a_message ("Hello from child\n");
print "Hello from invoked_as_pl.pl\n";
exit (0);
---------------end paste invoked_as_pl.pl