rschupp / PAR-Packer

(perl) Generate stand-alone executables, perl scripts and PAR files https://metacpan.org/pod/PAR::Packer
Other
48 stars 13 forks source link

Problems packing freetype library #67

Closed sciurius closed 1 year ago

sciurius commented 1 year ago

PAR::Packer 1.056, PAR 1.017, Strawberry 5.30.2, Windows10

I have a program that uses Imager. Imager demand loads backends for writing PNG files and font handling. It works fine when packed but other users reported problems with the font handling.

I've boiled it down to a small test program borrowed from the Imager tutorial (see below). I use the following pp settings:

--addfile=FreeSansBold.ttf
--module=Imager
--module=Imager::Font::FT2
--module=Imager::File::PNG

At least one user reports problems similar to

No font drivers enabled that can support this file, rebuild 
Imager with any of tt (FreeType 1.x), ft2 (FreeType 2.x) to use this 
font file at ...

Inspection shows that the generated exe does not include 'libfreetype-6__.dll`but I'm not sure that is relevant.

The attached zip contains the sample program, and associated files, plus the generated binary. prog.zip

shawnlaffan commented 1 year ago

The call below seems to work.

I ran objdump on all the .xs.dll files under the ...\site\lib\auto\Imager folder to get the set. This is using strawberry perl 5.32.1.1.

set dllpath=c:\perls\5.32.1.1_pdl\c\bin
pp --link %dllpath%\libpng16-16__.dll --link %dllpath%\libharfbuzz-0__.dll --link %dllpath%\zlib1__.dll --link %dllpath%\libbz2-1__.dll --link %dllpath%\libfreetype-6__.dll --link %dllpath%\libgraphite2__.dll --link %dllpath%\libfreetype-6__.dll --link %dllpath%\libt1-5__.dll -x --addfile=FreeSansBold.ttf -M Imager:: --module=Imager prog.pl
rschupp commented 1 year ago

@shawnlaffan thanks, you beat me to the punch

@sciurius Note you probably have to modify the dllpath environment variable in Shawn's recipe to match your configuration.

Just to explain the problem, PAR::Packer correctly packed the following DLLs into your prog.exe (just run unzip -l prog.exe):

   911872  2020-03-17 04:41   lib/auto/CryptX/CryptX.xs.dll
    23040  2020-03-17 03:23   lib/auto/Cwd/Cwd.xs.dll
    23552  2020-03-17 03:24   lib/auto/Fcntl/Fcntl.xs.dll
    30208  2020-03-17 03:24   lib/auto/File/Glob/Glob.xs.dll
    25088  2020-03-17 03:39   lib/auto/IO/IO.xs.dll
    89600  2022-09-14 15:26   lib/auto/Imager/File/PNG/PNG.xs.dll
    74752  2022-09-14 15:25   lib/auto/Imager/Font/FT2/FT2.xs.dll
   555520  2022-09-14 15:26   lib/auto/Imager/Imager.xs.dll
    54272  2020-03-17 03:48   lib/auto/List/Util/Util.xs.dll
    22016  2020-03-17 03:42   lib/auto/Math/BigInt/FastCalc/FastCalc.xs.dll
   251904  2020-03-17 04:20   lib/auto/Math/BigInt/GMP/GMP.xs.dll
   132096  2020-03-17 03:25   lib/auto/POSIX/POSIX.xs.dll
    43008  2020-03-17 03:44   lib/auto/Socket/Socket.xs.dll
    73216  2020-03-17 03:46   lib/auto/Win32/Win32.xs.dll
    76288  2020-03-17 03:26   lib/auto/Win32API/File/File.xs.dll
    26112  2020-03-17 03:26   lib/auto/mro/mro.xs.dll

These are the "glue" DLLs produced when you built and installed, for example, Imager/File/PNG/PNG.xs.dll from Image::File::PNG. This DLL actually links against the "real" PNG shared library, on your system that's libpng16-16__.dll. But PAR::Packer does not inspect PNG.xs.dll to detect this and hence doesn't pack libpng.dll into the executable. The executable will work fine on the machine you generated it on, because it's installed there, but it won't work on your user's machine (unless they have installed libpng.dll by chance). You can make this work by adding --link libpng16-16__.dll to your pp command line. It's actually more complicated since libpng*.dll itself links against the zlib compression library, zlib1__.dll on your system, so you have to add --link zlib1__.dll, too.

I should plug here Shawn's https://github.com/shawnlaffan/perl-pp-autolink tool, that will do the work for you to (recursively) detect dependent shared libraries, locate them on your machine and construct the necessary --link options.

shawnlaffan commented 1 year ago

pp-autolink had a bug where it was not scanning all the .xs.dll files on windows. It should be fixed in https://github.com/shawnlaffan/perl-pp-autolink/commit/387fd979300a625b925e3fbf976a64d28d80aa9b which I'll upload to cpan tomorrow, and once I check the related logic for other operating systems (and update the CI).

sciurius commented 1 year ago

Hi Roderich and Shawn, Thanks for your comments. Adding the extra dll's did, indeed, fix the problem.

I must admit I'm not familiar with Windows, I use it only occasionally to build releases of some of my software packages. PAR::Packer is a great help. I've tried pp_autolink (2.04 + patch 387fd97) but it did not find any libraries:

pp_autolink --output=prog.exe --module=Imager --module=Imager:: prog.pl
DLL check iter: 1
No alien system dlls detected

Detected link list:
CMD: pp --output=prog.exe --module=Imager --module=Imager:: prog.pl

Puzzling...

rschupp commented 1 year ago

I must admit I'm not familiar with Windows,

@sciurius Note that the problem is not specific to Windows, i.e. pp not packing dependent libraries. But on Linux for common libraries (e.g. libpng, zlib or libfreetype) you won't notice as they are typically installed on your user's machines (e.g. any graphical desktop would require these).

sciurius commented 1 year ago

Hmm. Apparently pp_autolink only processes --link and doesn't handle --module.

shawnlaffan commented 1 year ago

I've tried pp_autolink (2.04 + patch 387fd97) but it did not find any libraries:

It needs the -x flag to work in this case. Otherwise Module::Scandeps does not return the full set of libs.

Hmm. Apparently pp_autolink only processes --link and doesn't handle --module.

That would likely help with the above case. Patches welcome.

sciurius commented 1 year ago

Speaking of patches, this is something I severely miss at times:

--- lib/pp.pm~  2022-09-17 15:46:12.791363348 +0200
+++ lib/pp.pm   2022-09-17 16:32:15.863380766 +0200
@@ -14,7 +14,7 @@
 use PAR ();
 use Module::ScanDeps ();
 use App::Packer::PAR ();
-use Getopt::ArgvFile default=>1;
+use Getopt::ArgvFile default=>1, resolveEnvVars=>1;
 use Getopt::Long qw(:config no_ignore_case);

Rationale: I have options files that contain library links, eg.

--link=C:/Strawberry/perl/site/lib/Alien/wxWidgets/msw_3_0_2_uni_gcc_3_4/lib/wxbase30u_gcc_custom.dll
--link=C:/Strawberry/perl/site/lib/Alien/wxWidgets/msw_3_0_2_uni_gcc_3_4/lib/wxbase30u_net_gcc_custom.dll
--link=C:/Strawberry/perl/site/lib/Alien/wxWidgets/msw_3_0_2_uni_gcc_3_4/lib/wxbase30u_xml_gcc_custom.dll
...etc...

and I would rather have the physical location and version abstracted out, eg.

--link=${WXLIBS}/wxbase${WXLVV}_gcc_custom.dll
--link=${WXLIBS}/wxbase${WXLVV}_net_gcc_custom.dll
--link=${WXLIBS}/wxbase${WXLVV}_xml_gcc_custom.dll
...etc...

This is easier to maintain.

sciurius commented 1 year ago

BTW, is it normal that I have to disable Windows Defender to run pp?

pp --link c:\strawberry\c\bin/libgraphite2__.dll --link c:\strawberry\c\bin
/libfreetype-6__.dll --link c:\strawberry\c\bin/zlib1__.dll --link c:\strawberry
\c\bin/libpng16-16__.dll --link c:\strawberry\c\bin/libharfbuzz-0__.dll --link c
:\strawberry\c\bin/libbz2-1__.dll -o prog.exe prog.pl
The system cannot execute the specified program.
rschupp commented 1 year ago

BTW, is it normal that I have to disable Windows Defender to run pp?

I've seen several times that some packed executables trigger malware signatures (in your case of pp it's probably the intermediate executable that's run to determine the modules to pack into the FILE section of the final prog.exe) - nothing I can do about it.

sciurius commented 1 year ago

Hence the question: Is it normal? Apparently it is...

rschupp commented 1 year ago

Speaking of patches, this is something I severely miss at times: ... use Getopt::ArgvFile default=>1, resolveEnvVars=>1;

Done in 20d5707 - I didn't even know about this parameter.