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

I'm trying to produce an exe version of a script I've written and have run into trouble with the IPC::Run module. Both PAR::Packer and Perl2Exe produce errors with the code below:
#!/usr/bin/perl #perl2exe_include "attributes.pm"; use strict; use warnings; $|=1; use Symbol qw( gensym ); use IPC::Run qw( start ); use Tie::Handle; use IPC::Run::Win32IO; my %sp; $sp{'STDIN'} = gensym(); $sp{'STDOUT'} = gensym(); $sp{'STDERR'} = gensym(); my $h = start ['./cnc.exe'], '<pipe', $sp{'STDIN'}, '>pipe', $sp{'STDOUT'}, '2>pipe', $sp{'STDERR'} or die "returned $?"; sleep 20;
PAR::Packer generates the following when I attempt to run the resulting .exe:
Inappropriate I/O control operation: Win32::Process::Create() at C:\Us +ers\Izomiac\AppData\Local\Temp\par-4a6f7368\cache-6146a0a42031e00189f +f49a355f90de7875866db\inc\lib/IPC/Run.pm line 2143. Inappropriate I/O control operation: Win32::Process::Create() at C:\Us +ers\Izomiac\AppData\Local\Temp\par-4a6f7368\cache-6146a0a42031e00189f +f49a355f90de7875866db\inc\lib/IPC/Run.pm line 2244. Inappropriate I/O control operation: Win32::Process::Create() at C:\Us +ers\Izomiac\AppData\Local\Temp\par-4a6f7368\cache-6146a0a42031e00189f +f49a355f90de7875866db\inc\lib/IPC/Run.pm line 2244.

And Perl2Exe runs the .exe version dozens of times simultaneously.

For context, this script launches a half-dozen other scripts and coordinates communication between them by piping things through STDIN/STDOUT. I adopted this approach since one subprocess is a Tk GUI, another loads gigabytes of data into memory, and another is a 32 thread genetic sorting algorithm, and combining them into one process caused all sorts of instability. This version is faster and much more stable, but it's a big ask to have end-users install perl.

Any suggestions or alternatives?

Replies are listed 'Best First'.
Re: PAR-Packer and IPC-Run
by marto (Cardinal) on Oct 10, 2023 at 14:48 UTC

    Can you show how you used pp? Either pp-simple or try with the -x flag to help determine runtime dependencies.

    pp -x script_name.pl......
      I just did "pp script.pl -o script.exe". I tried the -x option just now but it didn't change the outcome. I also tried installing the tool you linked but Wx::Mini is a dependency and it won't install on my system.

        Try App::PP::Autolink. It is derived from pp-simple but has fewer dependencies. You might still need the -x flag.

Re: PAR-Packer and IPC-Run
by Marshall (Canon) on Oct 10, 2023 at 14:08 UTC
    So you have a program that runs in the Perl environment but not as an .exe. The most common cause of this is that some needed code hasn't been included within the .exe file. I would as a guess, add use Win32::Process before the use IPC statements. I don't have this version of run on my machine, can you say what Run.pm line 2143, line 2244 say?

      I tried including use Win32::Process and pp -M Win32:: without any luck.

      Line 2244 is an empty line. It's between two statements that are at the top of most of the subroutines:

      &_assert_finished; my IPC::Run $self = shift;
      And that subroutine doesn't appear to do anything too interesting.
      sub _assert_finished { my IPC::Run $self = $_[0]; croak "Harness not run" unless $self->{STATE} >= _finished; croak "Harness not finished running" unless $self->{STATE} == _fin +ished; }
      Line 2143 is: $? = $kid->{RESULT} = 0x0F;

      There are commented line numbers that are exactly 1337 lines different from the actual line numbers, which seems intentional, but those just lead to another empty line and an array declaration. =/

        Are you sure you are looking at the correct Run.pm ? There may be multiple instances of that file in your system ... you can always test by adding some debug message in it (perhaps just a die) and verify.

Re: PAR-Packer and IPC-Run
by Anonymous Monk on Oct 11, 2023 at 11:46 UTC

    Hm-m, suppose:

    use strict; use warnings; use IPC::Run qw( start ); my @c = qw( cmd /c sort ); my $h = start \@c, '<pipe', \*IN, '>pipe', \*OUT; print IN "zzz...\n"; print IN "hello world\n"; close IN; pump $h; print uc while <OUT>; close OUT; finish $h;

    to print uppercased sorted lines:

    HELLO WORLD ZZZ...

    But if packed to executable:

    pp -o pack_test.exe pack_test.pl

    the pack_test.exe gives:

    Inappropriate I/O control operation: Win32::Process::Create() at C:\Us +ers\me\AppData\Local\Temp\par-766164696d\cache-2f8c1556e4a094e1c7eee6 +ea88e299192e77e2e4\inc\lib/IPC/Run.pm line 2150. Inappropriate I/O control operation: Win32::Process::Create() at C:\Us +ers\me\AppData\Local\Temp\par-766164696d\cache-2f8c1556e4a094e1c7eee6 +ea88e299192e77e2e4\inc\lib/IPC/Run.pm line 2251.

    Looks like Win32::Process::Create wants absolute path at #345, and IPC::Run::Win32IO is overly optimistic to find it in $^X. Within PAR, this variable contains just 'perl.exe'. Even if there's no such file on the system.

    In fact, I don't know how to properly invoke perl from PAR bundle (it does contain all binaries, doesn't it), so here's a dirty hack. Somewhere at line #311, put

    local $^X = $ENV{ PAR_TEMP } . '\inc\perl.exe' if $^X eq 'perl.exe' and exists $ENV{ PAR_TEMP };

    And then pack like this:

    pp -M IPC::Run::Win32Pump -a C:\berrybrew\strawberry-perl-5.32.1.1-64b +it-PDL\perl\bin\perl.exe;perl.exe -o pack_test.exe pack_test.pl

    and then pack_test.exe kindly gives:

    HELLO WORLD ZZZ...

    I have no idea if it's IPC::Run or PAR::Packer (or Perl itself built on Windows) fault; and whether it'll work for your multi-gigabyte multi-threaded app; and how many refined professionals dropped unconscious because of ugliness of the above hack, but it's something to start with.

      That fixed it! You've saved me many hours of work in re-implementing the IPC to avoid using that module, which also would have lost STDERR monitoring. Thank you very much.


      Edit:
      Looks like that solved the compiling problem, and works great for the isolated example, but introduced a nasty memory leak in my actual script... 115 GB used in about 30 seconds before it failed by running out of memory. I suspect that might have been what messed up Perl2Exe since it basically kept relaunching my app like I'd put a while(1) loop around my code. I'll have to investigate further, the launcher component is purposefully kept as simple as possible and just handles launching and coordination. I appreciate your help as I didn't really know where to even start to fix that problem since I had no idea how the PAR environment differed from the standard PERL environment.