Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Problems running a packaged script.

by vitoco (Friar)
on Feb 06, 2019 at 12:51 UTC ( #1229476=perlquestion: print w/replies, xml ) Need Help??
vitoco has asked for the wisdom of the Perl Monks concerning the following question:

Hi! I'm having this problem again, and I cannot solve it this time...

Some years ago I wrote a script to extract some info from some objects at Salesforce.com using WWW::Salesforce module, and then PAR::Packer (pp) to build a standalone EXE to be run as a scheduled task in a Windows server. It was running OK until a week ago... logs said that it couldn't log in, but that only meant that some old APIs at Salesforce where removed, and I had to update something. Changes in the configuration trying to find a proper API only changed the error message. The original EXE was generated with pp in ActivePerl in a 32-bit machine, but a year ago I changed to Strawberry in x64, so my development PC is up to date and the plain perl script runs OK on it. So it's time to rebuild the EXE!!!

As the server where the script runs daily was also a x64 machine like my PC, I thought that an EXE build here would work OK, but it failed with the following message:

Can't load 'C:\Users\account\AppData\Local\Temp\par-636c7573746572\cac +he-792b3f8dca19082fb4a8fe816d16486838c5b752\48f12a51.xs.dll' for modu +le XML::Parser::Expat: load_file:The specified module could not be fo +und at C:/Strawberry/perl/lib/DynaLoader.pm line 193. ...

That was simple to solve. I just added -l libexpat-1__.dll to the pp command line, but the error turned into:

500 Can't locate object method "new" via package "LWP::Protocol::https::Socket" at WWW/Salesforce.pm line 103.

Googling around I found that setting environment variable PAR_VERBATIM could solve the missing "new" problem with other modules, but it didn't in my case, and I only got an EXE about 10% bigger than before.

I also tried to build a 32-bit EXE using a virtual machine, but the problem remained as it also had the same Strawberry perl version and the modules were up to date.

As I found that the EXE fails only on the server, where there perl is NOT installed (and it won't be), and it runs OK on machines with perl installed, I guess that something is not being included by pp in the EXE, but I cannot identify what... "-x" option of pp didn't help... the following messages are still present during the build:

# Use of runtime loader module Module::Runtime detected. Results of s +tatic scanning may be incomplete. # Use of runtime loader module Module::Implementation detected. Resul +ts of static scanning may be incomplete.

At some point of my tests, I unsuccessfuly added many other communications libraries to pp command: -l libexpat-1__.dll -l libcrypto-1_1-x64__.dll -l zlib1__.dll -l libssl-1_1-x64__.dll

Now I'm clueless... Any Idea?

Replies are listed 'Best First'.
Re: Problems running a packaged script.
by Lotus1 (Priest) on Feb 06, 2019 at 16:21 UTC

    Try including those two modules in your exe by using the -M option: e.g. -M Module::Runtime.

    Unfortunately PAR::Packer has a hard time with modules that are loaded dynamically. I've had good luck with using one command prompt with the portable version of Strawberry Perl running it's shell and another without. I run pp in the Strawberry shell and then test the exe in the non Strawberry shell. It sounds like you have installed Strawberry Perl so that won't work. But you might be able to find a way to run a command prompt and override the path so it can't find the Perl folders.

    Update: The Perlmonks module review for PAR mentions using -M and the POD for pp explains the details, including using '*' to include multiple modules from a namespace.

    Update 2: I'm getting the same error you posted: 500 Can't locate object method "new" via package "LWP::Protocol::https::Socket" at WWW/Salesforce.pm line 103. I created a simple two line program that just tries to log in with a fake test account.

    use strict; use warnings; use WWW::Salesforce; eval { WWW::Salesforce->login( 'username' => 'test','password' => '123 +4' ); }; print "> $@ <\n" if $@;

    The interesting thing is that there is no such thing as Socket.pm at "LWP::Protocol::https::Socket". I attempted to install that module when I noticed it was not on my system. When I run the script or the exe in the environment with Perl it works fine. I open a second command prompt and type set path=c:\temp. Then when I run the exe I get the error along with some popups about dlls I haven't linked yet.

    I also found a Perlmonks node related to this error.

Re: Problems running a packaged script.
by dasgar (Priest) on Feb 06, 2019 at 22:28 UTC

    It might be worth trying salva's Win32::Packer module to see if you might have better success.

Re: Problems running a packaged script.
by Lotus1 (Priest) on Feb 08, 2019 at 02:18 UTC

    I got it to work using the -M option of pp as I suggested in my first response. I noticed XML::Parser::Expat was mentioned in the first error you posted from running your script. Adding that module with the -M option fixed the problem.

    The pp command that worked was:

    pp -o salesforce.exe -M XML::Parser::Expat -l zlib1__.dll -l SSLEAY32_ +_.dll -l LIBEAY32__.dll -l libexpat-1__.dll salesforce.pl

    I ran pp in a normal command prompt and ran the exe in a second one where I cleared the 'path' environment variable so that no Perl libraries or modules would be found. Here is what I get from running the exe:

    C:\usr\pm\PAR>salesforce.exe > ORG_IS_SIGNING_UP: org is currently signing up at WWW/Salesforce.pm +line 110. <

    The script I packed to salesforce.exe is below for reference.

    use strict; use warnings; use WWW::Salesforce; eval { WWW::Salesforce->login( 'username' => 'test','password' => '123 +4' ); }; print "> $@ <\n" if $@;

      I got this work and explained my conclusions in this post of the thread.

      The final command line was:

      pp -a "C:/strawberry/perl/vendor/lib/Mozilla/CA/cacert.pem;cacert.pem" -l libexpat-1__.dll -l libcrypto-1_1-x64__.dll -l zlib1__.dll -l libssl-1_1-x64__.dll -o prog.exe prog.pl

      "-M" was not required, as XML::Parser::Expat was automagically recognized by pp, but its library was not, thus requiring "-l libexpat-1__.dll".

      I'm not sure if "cacert.pem" file is actually required by my script, and I guess that the use of "SSLeay" or "libssl" DLLs is decided by communication modules at runtime depending on availability.

        I didn't notice your post saying that you got it working before I posted my sucessful node. I'm glad you got it working and I'm interested to learn more about the -a option you used and how you inspected the contents of the temporary PAR caches.

        vitoco wrote:

        The final command line was: [...]
        You seem to be implying it is the only correct way. My approach with -M also works and the -M clause is required for my approach.

        vitoco wrote:

        "-M" was not required, as XML::Parser::Expat was automagically recognized by pp, but its library was not, thus requiring "-l libexpat-1__.dll".
        I tried -M with the Expat module and without the Expat dll and it didn't work. Just the dll didn't work but with both the dll and the -M for the module it did work. There is obviously something included with the module that isn't included in the dll. And XML::Parser::Expat must not have been packed with all of its dependencies since it works with it for me but not without it. My approach didn't need as many dlls linked also. Likely they or some alternatives were included instead. with the -M option.

        I suppose semantically you are correct that '-M' was not required since you found a different way that works. But that doesn't invalidate my approach and for my approach '-M' was required. My approach was very quick also. I spent a few minutes adding the -M option with the expat module and had it working whereas you only got your pp exe to work by comparing with the output from pp_autolink.

        Communications modules like SOAP::Lite (which is the source of problems here) need to be able to handle many different protocols using different modules. To do this they try different ones until one works. This is what causes the problem since no one module is needed but at least one path is needed. Making all of the communications modules requirements means many unneeded modules would have to be installed to get SOAP::Lite to work.

        It is likely that the way your exe runs on the server is not using the same modules as when you run it in your development environment. I don't remember which but some of the modules I found listed with 'require' statements in SOAP::Lite were not installed on my machine and the script was running. I also found internet forum threads about the same error message that suggested fixes with modules that are not in my Perl environment. So that told me there are different modules that can fix this problem. I only needed to get the ones I already had packed into the exe.

        I recently used pp to solve a similar difficult to pack script that used Data::GUID::Any. This module also had many optional modules that it could use to create GUIDs but I had to pack some of them with the -M option to get it working with pp. This was an interesting challenge and I'm glad to learn more about the -a option you used and your approach of comparing the temp PAR caches. I also plan to try pp_autolink.

Re: Problems running a packaged script.
by Anonymous Monk on Feb 06, 2019 at 18:08 UTC

      I've just tried it, unsuccessfully! :-(

      I had to install some missing modules to run this tool and lots of dependencies, including Wx!!!

      As far as I could understand, this utility finishes after the EXE was created, but I didn't get any (at least in my working dir). Reviewing STDERR, I found that it finishes with the following line:

      UH OH empty ARRAY(0x530b488) []  at C:\WorkingDir\ppsimple.pl line 131.

      Checking STDOUT, I could see many DLLs as dependencies, but the expected "libexpat-1__.dll" was not between them. I couldn't identify other ones that should be forced to pp.

      Did I do something wrong?

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1229476]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (5)
As of 2019-02-22 20:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    I use postfix dereferencing ...









    Results (119 votes). Check out past polls.

    Notices?