http://qs321.pair.com?node_id=758312

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

Folks-

Can anyone use perlapp and successfully build a working *.exe for any perl script that uses both POE and Tk?

I can't, and am very confused and frustrated.

Step 1: Get a working Perl/POE/Tk program not written by me (...well mostly)

The POE Cookbook is the most logical place to find something. Unfortunately the existing sample program doesn't work on either MacOS or Windows right out of the box (the GUI window never shows up). I had to add some (poe_main_window->update)'s in it to give it basic functionality. I also added a check to error out if poe_main_window is not defined (for reasons that will become apparent later on). This version seems to work fine:
# http://poe.perl.org/?POE_Cookbook/Tk_Interfaces # # This sample program creates a very simple Tk counter. Its interface # consists of three widgets: A rapidly increasing counter, and a # button to reset that counter. use warnings; use strict; # Tk support is enabled if the Tk module is used before POE itself. use Tk; use POE; # Create the session that will drive the user interface. POE::Session->create ( inline_states => { _start => \&ui_start, ev_count => \&ui_count, ev_clear => \&ui_clear, } ); # Run the program until it is exited. $poe_kernel->run(); exit 0; sub ui_start { my ( $kernel, $session, $heap ) = @_[ KERNEL, SESSION, HEAP ]; if(! defined($poe_main_window)) { die "\$poe_main_window not defin +ed" }; $poe_main_window->Label( -text => "Counter" )->pack; $heap->{counter_widget} = $poe_main_window->Label( -textvariable => \$heap->{counter} )->p +ack; $poe_main_window->Button ( -text => "Clear", -command => $session->postback("ev_clear") )->pack; $poe_main_window->update; $kernel->yield("ev_count"); } # Handle the "ev_count" event by increasing a counter and displaying # its new value. sub ui_count { $_[HEAP]->{counter}++; $poe_main_window->update; sleep(1); $_[KERNEL]->yield("ev_count"); } # Handle the "ev_clear" event by clearing and redisplaying the # counter. sub ui_clear { $_[HEAP]->{counter} = 0; }

Step 2: Figure out how to use perlapp on it

This wasn't as easy as I thought it should be. At first, I just simply kept on adding modules using the --add module command-line options for perlapp. I ended up with this:
perlapp --add "POE::Wheel" --add "POE::Loop::Tk" --add "POE::Loop::Sel +ect" --add "POE::Resource::Aliases" --add "POE::Resource::Events" --a +dd "POE::Resource::Extrefs" --add "POE::Resource::FileHandles" --add +"POE::Resource::SIDs" --add "POE::Resource::Sessions" --add "POE::Res +ource::Signals" --add "POE::Resource::Statistics" --add "POE::Session +" --add "POE::Driver::SysRW" --add "POE::Filter::Line" --verbose --cl +ean --force --lib lib --exe tst121.exe tst121.pl
Which will successfully create a windows executable for me.

However, anytime it is run it will die claiming that poe_main_window is not defined (remember the error check I added?). Oh, and also note that the *.pl script works fine and the *.exe doesn't on the same machine. Grrrrr.

Step 3: Google

As is typical for me, I resort to finding others who've solved the same problems that I'm experiencing. Hmmm, not a lot of useful stuff here. Lots of old links talking about using the POE::Preprocessor which doesn't seem to be around anymore (according to this web page).

In fact, I have already asked about this problem here at perlmonks, without really knowing it is a poe_main_window problem. In that code, you'll notice I did a sneaky thing with the lines:

# WHY DO I HAVE TO DO THIS???? my $top = $poe_main_window || MainWindow->new();
In Rocco's response he questioned this, but I never followed up (Note-to-self: NEVER use MainWindow->new() when POE is in the mix...).

Step 4: Perlmonks

Ask the experts.

So... it it possible to do this, and if so, how?

Many thanks!

-Craig

Replies are listed 'Best First'.
Re: POE & Tk totally confound perlapp (or am I missing something?)
by rcaputo (Chaplain) on Apr 17, 2009 at 18:41 UTC

    Off the top of my head, where you do --add "POE::Loop::Select", you probably should do --add "POE::Loop::TkActiveState" instead.

    Untested, as my Windows VM is currently offline.

      Rocco-

      Thanks for the help! I tried replacing the POE::Loop::Select with POE::Loop::TkActiveState, but that didn't make a difference, so I put things back the way they were.

      Looking at the original perlapp output, I noticed that POE::Loop::TkActiveState is already included. Here is the complete list (for future reference):

        That seems helpful.

        You should definitely not include POE::Loop::Select, since it's mutually exclusive of POE::Loop::TkActiveState.

        Can you force PerlApp to exclude modules? It may be that perlapp is too aggressive about including modules it finds in the source code, including POE::Loop::Select when it shouldn't be used.

        perlapp's output includes a number of errors, many of them within Tk. For example:

        +++ C:\Perl\lib\auto\Tk\tabFocus.al auto\tk\tk.dll: error: Case mismatch between module and file name refby: C:\Perl\lib\Tk.pm file: C:\Perl\lib\auto\Tk\Tk.dll

        That shouldn't be an issue on Windows, which uses a case-insensitive filesystem. I don't know whether it's significant for PerlApp, though.

        Maybe we can narrow this down to a POE issue vs. a Tk issue? Have you tried bundling up a program that uses POE by itself? Have you tried bundling up a Tk program that doesn't use POE? Do they work separately?

Re: POE & Tk totally confound perlapp (or am I missing something?)
by Marshall (Canon) on Apr 18, 2009 at 03:42 UTC
    I haven't used POE, but have built a number of Tk apps in .exe form using ActiveState. I don't mess around with manually editing the --add command line stuff. I put explicit "use" statements in the code. In the case of Tk, although just "use Tk;" is enough when running in normal environment, to make the .exe I find that I need to "use" all of the individual widgets that the program calls...like below.. You may find that "using" the module in the code produces a different result than --add does. Your mileage may vary, but I would suggest trying this approach.
    use Tk; use Tk::TableMatrix; use Tk::LabFrame; use Tk::Listbox; use Tk::Scrollbar; use Tk::Button; use Tk::Menubutton; use Tk::Menu; use Tk::Widget; use Tk::Label; use Tk::Entry; ...etc..
    UPDATE:
    I looked at one of my .PerlApp files. Now I am on 7.1 and haven't installed the latest version yet...BUT this is a real product in its 2nd year of production. The project code name is "green" which of course means nothing to you. I took out some path names, but this is basically what your .PerlApp file should look like.

    Notice: this .exe is not dependent on anything, there are no dynamic .dlls's, AND nothing has been "forced" into the .exe. This Gui: 0 stuff means that there is a command window that starts also (ie, this is not a strictly GUI only application). Hostname "bigmomma" is just the name of my build machine.

    Your .PerlApp file should look like this...very clean...no voo-doo.

    As far as path goes, in the PerlApp application, C:\Perl\site\lib;C:\Perl\lib;.

    In other words, this builds from the standard libraries and accesses current directory for non_standard ones (they could be in a different directory).

    Hope this helps! When your .PerlApp file looks as clean as this, you will have a working .exe file.

    #!C:\Program Files\ActiveState Perl Dev Kit 7.1\bin\lib\pai.exe PAP-Version: 1.0 Packer: C:\Program Files\ActiveState Perl Dev Kit 7.1\bin\perlapp.exe Script: green.pl Cwd: C:\PROJECTS\XYZZY1\XYXXY2\XYZZY_experimental Clean: 0 Date: 2008-08-28 21:51:03 Debug: Dependent: 0 Dyndll: 0 Exe: green.exe Force: 0 Gui: 0 Hostname: bigmomma Icon: GREENLOGS.ICO Icon: GREENLOGS.ICO No-Compress: 0 No-Logo: 0 Runlib: Shared: none Tmpdir: Verbose: 0 Version-Comments: ............. Version-CompanyName: .............. Version-FileDescription: version 2.01 green Version-FileVersion: 2.1 Version-InternalName: .............. Version-LegalCopyright: ........... Version-LegalTrademarks: ............. Version-OriginalFilename: Green Version-ProductName: Green Version-ProductVersion: 2008 Xclude: 0
Re: POE & Tk totally confound perlapp (or am I missing something?)
by cmv (Chaplain) on Apr 18, 2009 at 18:08 UTC
    Marshall++
    rcaputo++

    Thank you both for the help.

    I believe this is a POE issue, as I've been perlapp-ing tk products for some time now.

    In fact, you can actually get this to run if you use that trick I spoke about earlier. Instead of expecting poe_main_window to be there, simply set it yourself:

    my $poe_main_window = MainWindow->new();

    If you do this, the application will come up and run somewhat correctly. A better example of running somewhat correctly is in the pogram listed in my previous question, you'll see that everything works fine, but when the input stops, you can't scroll. I believe this has to do with the warning that Rocco puts in his documentation about not using MainWindow->new directly (that's my gut feeling, but I'm not sure).

    My goal is to put together something similar to what is in my previous question, but I wanted to start at ground zero first, and figure out how to build a simple app with POE and Tk correctly.

    I really appreciate the help on this, as I have to have something ready by the end of the month. If I can't get this to work with POE and Tk, I'll have to pull out the POE stuff (which I really don't want to do).

    Thanks

    -Craig

    Update: Also, I believe it's true that just because perlapp includes a module, doesn't mean it is forced to be used. My understanding is that perlapp can include many modules, even ones that the application never uses (just excess baggage). It's just providing the environment for the perl script to run. If this is true, then it wouldn't matter that perlapp is including two mutually exclusive modules (POE::Loop::Select and POE::Loop::TkActiveState) and the application would just choose which one it wants to use.

    My current gut feeling is that I just need to be including something that I'm not. I have no idea what that could be though...

Re: POE & Tk totally confound perlapp (or am I missing something?)
by zentara (Archbishop) on Apr 21, 2009 at 21:47 UTC
Re: POE & Tk totally confound perlapp (can anyone help?)
by cmv (Chaplain) on Apr 21, 2009 at 14:40 UTC
    Folks-

    I still can't solve this problem and time is getting short. I've reduced the problem down to the following:

    use warnings; use strict; use Tk; use POE; if(! defined($poe_main_window)){die "\$poe_main_window not defined" };
    If I run this as a perl script on windows XP, it works fine (meaning I get no output).

    If I perlapp this and run the executable on windows XP, it dies with the given error message. I can't figure out why.

    Any thoughts on how to proceed to debug this, or how to solve it would be greatly appreciated.

    Thanks

    -Craig

SOLVED: POE & Tk totally confound perlapp (or am I missing something?)
by cmv (Chaplain) on Apr 22, 2009 at 18:56 UTC
    Folks-

    This problem was solved off of the POE mailing list by Andrew F.

    It turns out that POE::Kernel tries to figure out which event loop to use, if none is specified. It was guessing correctly from the *.pl file, but incorrectly from the *.exe file (it tried to use the default POE::Loop::Select). I don't know what perlapp does to make POE::Kernel guess incorrectly, but to solve the problem you simply force POE::Kernel to use the correct event loop. Here is Andrew's solution (also note all the "use" statements so you don't have to put all those "--add" command line options on your perlapp line):

    use warnings; use strict; use Tk; use POE qw (Loop::TkActiveState); use POE::Loop::TkActiveState; use POE::Kernel; use POE::Session; use POE::Resource::Aliases; use POE::Resource::Events; use POE::Resource::Extrefs; use POE::Resource::FileHandles; use POE::Resource::Sessions; use POE::Resource::SIDs; use POE::Resource::Signals; use POE::Resource::Statistics; if(! defined($poe_main_window)) { die "\$poe_main_window not defined" +};
    Thanks Andrew!

    -Craig