Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Re: dll not embedded in PAR::Packer's output

by RonW (Parson)
on Dec 01, 2015 at 18:51 UTC ( [id://1149056]=note: print w/replies, xml ) Need Help??


in reply to dll not embedded in PAR::Packer's output

Since you are packaging a large-ish application, it would probably be better to create an installer that makes a self-contained folder tree with your application, Perl and the libraries you depend on.

(Executables created by pp (or perl2exe or similar) have a long startup time because everything bundled in to the exe file has to be extracted to a temporary folder, first. Also, creating an installer will give you more control.)

In the past, I have used the "portable edition" of Strawberry Perl as a base for creating installers for custom Perl installations under Windows. Including your application as part of such a custom Perl installer would not be much more work.

Disclaimer: Last time I did this was well over a year ago, so I've forgotten some details. I found the information I needed by searching the web and reading various scripts in the portable Perl installation.

What I remember about what I did:

  1. "Installed" the "portable edition" of Strawberry Perl on a Windows PC that had no other Perl installed.
  2. Launched the .bat file in PESP to start a command console to run Perl commands.
  3. Used cpan to install needed modules.
  4. Copied known required DLLs to the bin folder.
  5. You can copy your Perl programs to the bin folder. Then test that it works. Add any missing DLLs and test again.
  6. Made a copy of the above mentioned .bat file to SetUp.bat
  7. Modified this new SetUp.bat to perform needed set up actions, including running a Perl program that adds entries to the Windows registry.
  8. Created a README.txt file saying to run the SetUp.bat file.
  9. Created a zip file of the customized Perl installation.
  10. Copied the zip file to another PC with no Perl, extracted it, ran SetUp.bat and tested several Perl programs to make sure they ran correctly. And test your program. If any DLLs are missing, go back, add them to the bin folder, create a new zip file and test it.
  11. Distributed the zip file with the instructions to extract to c:\CompanyPerl and read the README.txt file.

If this is too hard for your users, try rewriting SetUp.bat as SetUp.pl, then use pp -a CompanyPerl.zip SetUp.pl to create a SetUp.exe - then test it on another PC

If your users demand a "proper" Windows installer, you can use, for example, 7-zip or NSIS, to create a Windows installer.

Once the initial install is done, more Perl programs can be "installed" by copying them to the bin folder in the custom Perl installation.

Replies are listed 'Best First'.
Re^2: dll not embedded in PAR::Packer's output
by afoken (Chancellor) on Dec 01, 2015 at 21:08 UTC

      Had not heard of Inno Setup before. Thanks.

      I had used NSIS once, years ago, but was a lot of work. Then I discovered that 7-zip files can be converted into installers. Basically, it's a variant of a self-extracting archive that auto-runs a cmd file (like a bat file) after the extraction. Was not a lot of work. I had the cmd file set some environment variables, copy files, then start a Perl program to finish the installation.

        I discovered that 7-zip files can be converted into installers. Basically, it's a variant of a self-extracting archive that auto-runs a cmd file (like a bat file) after the extraction.

        Yes, that's exactly what my old AP+app installer did using WinZIPs SFX function. Perl can quite easily be embedded into a batch script, and as far as I remember, that was how the installer script worked. A batch file with embedded code that first did some minimal sanity checks using the batch interpreter, then executed perl -x -S %0, letting perl search and execute the embedded perl script in the batch file.

        This is a quite minimal example showing the trick:

        @echo off echo Hello from the DOS/Windows command interpreter perl -x -S %0 goto batchend #!perl use strict; use warnings; print "Hello from Perl\n"; exit; __END__ :batchend echo Back from perl in the command interpreter

        When installing from an unpacked ZIP, that batch usually runs from a temporary directory (not a big problem), and the perl executable from the ZIP is not in $ENV{PATH}. That can be a problem. Just starting the installer script as shown above will either run some other perl installed by some other application (Oracle delivered REALLY old perls at that time), or perl won't simply run.

        You really don't want to mix two or more perls on a Windows machine, so the first thing you do (or better: I did years ago) was to try to run the "resident" perl, expecting it to fail:

        rem -- somewhere inside the big batch file -- perl -e "exit 42" if errorlevel 43 goto noperl if errorlevel 42 goto badperl goto noperl :badperl echo Sorry, there is a foreign perl installed. Can't install. goto fail :noperl rem ... rem ... much code omitted, explained in the next step rem ... :fail pause :end

        DOS is strange: if errorlevel 43 does NOT check that the exit code of the last program is exactly 43, but if the exit code is at least 43. So the first if errorlevel 43 catches exit codes from 43 to 255, the next if errorlevel 42 can catch only exit code 42 (all above were alredy handled), and the final goto noperl catches all exit codes below 42. The check for 42 is quite arbitary, usually the exit code is 0, 255, or something much larger on NT. But it is very unlikely that some program named perl.com or perl.exe exits with exit code 42, given the parameters, and can't interpret perl.

        Note that the batch doesn't yet use the embedded script trick, because there can be only one embedded script.

        Another step is to make sure that the script finds itself and the other files extracted from the ZIP file. SFX modules should run the embedded script with the temporary directory as the current directory.

        Quite easy:

        rem ... rem (assuming this script is named setup.bat) if exists setup.bat goto havesetup echo Can't find myself. Can't install. goto fail :havesetup rem (assuming our perl.exe is in a bin subdirectory) if not exists perl.exe goto dirsok echo ZIP file was unpacked without directories. Can't install. goto fail :dirsok if exists bin\perl.exe goto haveperl echo Missing my perl.exe. Archive damaged? Can't install. goto fail :haveperl rem ... rem ... use perl to bootstrap itself rem ... :fail pause :end

        Quite easy: Check that the batch file exists in the current directory, and that perl.exe was extracted to the bin subdirectroy, not to the current directory. At that point, the unpacked perl should be usable.

        Perhaps one last paranoia check?

        rem ... bin\perl.exe -e "exit($]!=5.014002)" if not errorlevel 1 goto perlok echo Unexpected perl interpreter found. Won't install. goto fail :perlok rem ... :fail pause :end

        Just a version check. perl.exe will exit with exit code 0 only if it has exactly the right version. Else, it will exit with exit code 1, maybe larger if something strange has happened (crashing perl).

        And now, the embedded script. perl -x will search the entire file for the first line starting with #! and containing the word "perl". From there, it will start interpreting perl. The -S parameter will make perl search $ENV{PATH} for the script. Not strictly required.

        Errors should be reported. Perl has die, so that's not a big problem. But the command window should stay open on error. The batch file has a fail label that does exactly that, and die sets the exit code to non-zero. Easily combined:

        rem ... perl -x -S %0 if errorlevel 1 goto fail goto end rem -- command shell will never try to interpret this or the following + lines up to the fail label. #!perl use strict; use warnings; use lib 'lib'; use My::Custom::Setup; My::Custom::Setup->run(); __END__ rem ^-- perl stops interpreting at __END__ :fail pause end

        The embedded script here is quite minimal, it just loads a custom module that does the actual work. You can also combine a batch skeleton and a larger perl script, perhaps using a primitive template system, or just by concatenating batch header, perl script, and batch footer into the final setup.bat. But that makes it a little bit harder to use an editor with syntax highlighting. Most won't correctly display both languages at the same time.

        Another option is to setup or load a custom error handler that displays a message box instead of just writing into the DOS box. Carp can be quite inspiring, but a simple eval may be sufficient. The string eval prevents compile time effects of use, so even compile errors in lib and My::Custom::Setup are trapped by eval.

        #!perl use strict; use warnings; if (eval q[ use lib 'lib'; use My::Custom::Setup; My::Custom::Setup->run(); 1; ]) { exit(0); } else { my $err=$@; Win32::MsgBox($err,MB_ICONSTOP,"Error"); die $err; } __END__

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1149056]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (8)
As of 2024-04-23 12:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found