Lazarus

Free Pascal => Unix => Topic started by: tk on January 14, 2017, 02:04:01 pm

Title: [SOLVED] Linux binaries too big
Post by: tk on January 14, 2017, 02:04:01 pm
Hi, of course I know about http://wiki.lazarus.freepascal.org/Lazarus_Faq#Why_are_the_generated_binaries_so_big.3F etc. but I still wonder why generated binary of the same lpi project (my case is shared library) is roughly 3 times bigger for Linux target than for Windows target.

i386-linux/libmylib.so 6686916 bytes
i386-win32/mylib.dll 2157056 bytes

When I inspect the *.so ELF:
- 3151152 bytes are taken by PROGBITS/.text section
- 1517624 bytes by PROGBITS/.data section
- 1352880 bytes by REL/.rel.dyn section
- 337740 bytes by PROGBITS/.rodata section
- 207160 bytes by PROGBITS/fpc.resources section
- 113460 bytes by NOBITS/.bss section
another section sizes are small (below 65536 bytes).

When I inspect the *.dll PE:
- 1463808 bytes are taken by .text section
- 370176 bytes by .rdata section
- 159232 bytes by .rsrc section
- 105984 bytes by .reloc section
again another section sizes are small (below 65536 bytes).

I don't have problem with it but I am just interested why these sizes are so different.
Title: Re: Linux binaries too big
Post by: marcov on January 14, 2017, 02:48:12 pm
Some possibilities in decreasing order

Considering the considerable size difference I'd say it is one of the first two.

 Note that the first (smartlinking) goes for all used components (FPC rtl+packages+lcl+whatever you compiled yourself), not just your project.

Generating a map file might also give some info.

Title: Re: Linux binaries too big
Post by: Leledumbo on January 14, 2017, 05:21:31 pm
Smartlinking and debug info (which often improperly stripped) indeed. Properly smartlinked and stripped debug info should have similar size on platforms with identical bitness (even under different bitness, the difference shouldn't be 300%). Example from one of my projects:
https://bitbucket.org/leledumbo/erd-maker/downloads
Title: Re: Linux binaries too big
Post by: tk on January 14, 2017, 06:38:47 pm
I made further observations with fresh projects - see attachments. And it looks like the problem applies only for a shared library (DLL vs. SO), for normal executable there is no significant difference.

My executable project binaries now have ca. 2 MB in size both for Win and Linux and for shared library the DLL size is 1.7 MB and SO size is 5.4 MB.

I tried almost everything, played with -Cx,-XX,-Xs,-WR,another optimization levels,rebuild,clean up+rebuild...

Using now FPC r35280 from yesterday.

Could it be some issue with PIC? I don't have -fPIC enabled for the library but when I add it to the compiler options the SO size does not change. So is it possible that FPC generates PIC for Linux target implicitly?

This is my Linux compiler option string for the library:
Code: [Select]
-MObjFPC -Scghi -CX -O3 -Xs -XX -l -vewnhibq -Filib/i386-linux -Fu/home/osboxes/Documents/lazarus/lcl/units/i386-linux/gtk2 -Fu/home/osboxes/Documents/lazarus/lcl/units/i386-linux -Fu/home/osboxes/Documents/lazarus/components/lazutils/lib/i386-linux -Fu/home/osboxes/Documents/lazarus/packager/units/i386-linux -Fu. -FUlib/i386-linux -olibproject1.so -dLCL -dLCLgtk2
Title: Re: Linux binaries too big
Post by: Phil on January 14, 2017, 08:00:49 pm
I made further observations with fresh projects - see attachments. And it looks like the problem applies only for a shared library (DLL vs. SO)

I can confirm this. My 64-bit dynamic libraries (.so) on Linux are always about 2x the size of 64-bit .dll on Windows or 64-bit .dylib on OS X.

With OS X, -XX passes -dead_strip to the linker. With Linux, -XX passes --gc-sections to the linker. The man notes for ld suggest that --gc-sections does not apply to dynamic libraries. No apparent restriction like that for Mac's -dead_strip though.

Add -k--print-gc-sections to FPC command line to see what gets stripped out with a normal executable when -XX is used (--gc-sections).

Title: Re: Linux binaries too big
Post by: minesadorada on January 14, 2017, 08:43:55 pm
I use UPX as an External Tool in Lazarus to shrink compiled files. You can associate it with a key (I use NumLock)
Its free and open source.

https://upx.github.io/
Title: Re: Linux binaries too big
Post by: Cyrax on January 14, 2017, 10:58:27 pm
I use UPX as an External Tool in Lazarus to shrink compiled files. You can associate it with a key (I use NumLock)
Its free and open source.

https://upx.github.io/

And say hello for dozen complaints from users who uses paranoid antivirus suites. IMHO, do not use executable packers. They can cause problems with antivirus programs.
Title: Re: Linux binaries too big
Post by: lainz on January 15, 2017, 12:01:49 am
Quote
And say hello for dozen complaints from users who uses paranoid antivirus suites. IMHO, do not use executable packers. They can cause problems with antivirus programs.

That's true. I needed to talk with various AV companies to say that my application was safe. There's a category specific for "UPX-Packed" kind of virus.
Title: Re: Linux binaries too big
Post by: Akira1364 on January 15, 2017, 02:41:37 am
Yeah, never ever use UPX. As has been stated already in this thread, UPX-compressed executables are widely viewed as "infected" automatically by a number of AV suites. I'm pretty sure this is a direct result of the fact that UPX was extensively used by a variety of malware authors in the early to mid 2000s (Most of them from Russia for some reason, and much of the code in Delphi, believe it or not!) Also, UPX-compressed executables quite often have noticeably reduced startup times, and can also cause what's known as "disk thrashing" (depending on the nature of the application itself, of course.) If anyone out there is using it with the intention of "protecting" their FPC-built application: chill out. No one is going to decompile it. While it's true that there are quite a few applications able to do high-quality decompilation of Delphi code, the same cannot be said for FPC. I am not aware of any notable decompiler that even recognizes FPC-compiled code specifically at all. (IDA, for example, tends to think it's GCC code when the executable is linked with dwarf or stab debug symbols, and Visual C++ code when it's been stripped.)
Title: Re: Linux binaries too big
Post by: minesadorada on January 15, 2017, 07:53:19 am
I use UPX as an External Tool in Lazarus to shrink compiled files. You can associate it with a key (I use NumLock)
Its free and open source.

https://upx.github.io/ (https://upx.github.io/)

And say hello for dozen complaints from users who uses paranoid antivirus suites. IMHO, do not use executable packers. They can cause problems with antivirus programs.
So not a problem for Linux executables (which is the topic subject)
Your comments are sound for Windows executables.
Title: Re: Linux binaries too big
Post by: tk on January 15, 2017, 11:01:46 am
I can confirm this. My 64-bit dynamic libraries (.so) on Linux are always about 2x the size of 64-bit .dll on Windows or 64-bit .dylib on OS X.
Yes, my dylib/OS X version of the shared library is about 2.9 MB, that is only slightly bigger than the Windows binary. Only Linux binaries are so big.

Add -k--print-gc-sections to FPC command line to see what gets stripped out with a normal executable when -XX is used (--gc-sections).
I can see lot of these messages for the executable but none for the shared lib:
Code: [Select]
/usr/bin/ld: Removing unused section ...
So it really seems that -XX has no effect for shared libraries on Linux.
Quote
--gc-sections decides which input sections are used by examining symbols and relocations. The section containing the entry symbol and all sections containing symbols undefined on the command-line will be kept, as will sections containing symbols referenced by dynamic objects. Note that when building shared libraries, the linker must assume that any visible symbol is referenced. Once this initial set of sections has been determined, the linker recursively marks as used any section referenced by their relocations. See --entry and --undefined.
So as far as I understand this it is clearly a linker issue, which cannot be influenced by the compiler and we must count with bigger sizes of shared libraries on Linux.

UPX:
I know about it but as I said, the bigger sizes are not a problem for me/us. I just wanted to know why the Linux shared library binaries are so big. Today's hard disks are very big and I/we always use installers/packagers to decrease the size of the binaries for distribution. So I don't see the need for upx anymore...
Title: Re: Linux binaries too big
Post by: Thaddy on January 15, 2017, 12:00:44 pm
Note this very important quote from Marco:
Quote
Note that the first (smartlinking) goes for all used components (FPC rtl+packages+lcl+whatever you compiled yourself), not just your project.
You really need to build EVERYTHING including all Lazarus libraries with -CX -XX -Xs.
You will find that only in that case the executable size approaches that on Windows.
I always do that from the command-line and a specific configuration.

Also, try to optimize it with whole program optimization. (not straightforward to do, but not rocket science either)
Title: Re: Linux binaries too big
Post by: tk on January 15, 2017, 12:34:04 pm
You really need to build EVERYTHING including all Lazarus libraries with -CX -XX -Xs.
You will find that only in that case the executable size approaches that on Windows.
I always do that from the command-line and a specific configuration.

I am pretty sure I did this but one never knows, that's why I am asking here.
Can you confirm the binary size approaches that on Windows for a Linux build of the shared library I attached im my previous post or any of your shared libraries, on your Linux system?
If yes please specify exact instructions how to build them.

I repeat we are talking now only about shared libraries, not executable programs.
Title: Re: Linux binaries too big
Post by: marcov on January 15, 2017, 02:04:09 pm
So as far as I understand this it is clearly a linker issue, which cannot be influenced by the compiler and we must count with bigger sizes of shared libraries on Linux.

If it is true, it has not been verified yet. The problem is that it is not just an OS difference, but also the way how FPC was build ON that OS.

In that, Thaddy is right, the observations only count if it has been proven without a doubt that the whole system is built with smartlinking.


Title: Re: Linux binaries too big
Post by: tk on January 15, 2017, 02:22:27 pm
Wait, do I have to rebuild FPC itself with smartlinking? This I did not! But even if this would matter, then why is the size of EXE similar as on Win and the size of DLL so different? Note that, of course, I compiled both of the attached fresh projects with the same compiler.

Also note that I get the same results both for the compiler built on Linux and the Linux crosscompiler built on Windows. Both compilers were built in a "default" way (on Linux with make clean all and on Windows with fpcupdeluxe).
Title: Re: Linux binaries too big
Post by: Thaddy on January 15, 2017, 04:09:00 pm
First: the compiler itself does not matter but the RTL and FCL and the FPC packages should...be build with -Cg -Xc -XX -CX and maybe -Xs
Second: Why would you need Forms and Interfaces in a shared library? That is bad practice: It will pull in ALL code, since a shared library will never be able to distinguish what you need.
A simple shared library is a few KB on Linux. Add classes for some Pzazz and it is still under 1 MB. (867 KB on ARM-LINUX.Note it still pulls in ALL of classes)
Code: Pascal  [Select][+][-]
  1. library project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   Classes{, Forms, Interfaces //are bad design!! for a shared library}
  7.   { you can add units after this };
  8.  
  9. begin
  10. end.  

The template for a shared library looks plainly stupid for Linux, but also in general.
Sensible programmers won't put any GUI code in a shared library. Unless it IS the shared library, e.g. GTK+ or QT.
Title: Re: Linux binaries too big
Post by: tk on January 16, 2017, 01:53:49 pm
First: the compiler itself does not matter but the RTL and FCL and the FPC packages should...be build with -Cg -Xc -XX -CX and maybe -Xs

Could you achieve with these options, that the compiled shared library under Linux has similar size as on Windows? I've rebuilt whole FPC (which means compiler+rtl+packages) with options -CX -XX -Xs (options -Cg and -Xc were not accepted and always resulted in misc. compilation errors) then took these options for my project and made Clean+Rebuild. And did not succeed, binary size is still around 3x bigger for a SO than for a DLL.

Second: Why would you need Forms and Interfaces in a shared library? That is bad practice: It will pull in ALL code, since a shared library will never be able to distinguish what you need.

I have good reasons why to do that for some of my libraries, but that is not the issue we discuss here. The same difference (SO 3x bigger than DLL) I see for any library, whether LCL is included or not.

A simple shared library is a few KB on Linux. Add classes for some Pzazz and it is still under 1 MB. (867 KB on ARM-LINUX.Note it still pulls in ALL of classes)
Unfortunately I do not have simple libraries. Compare library size for a library that takes min. 200kB on Windows. What takes it on your Linux then?

The template for a shared library looks plainly stupid for Linux, but also in general.
The default library template in Lazarus of course comes without any LCL dependency.
Title: Re: Linux binaries too big
Post by: Thaddy on January 16, 2017, 02:38:57 pm
Quote
Unfortunately I do not have simple libraries. Compare library size for a library that takes min. 200kB on Windows. What takes it on your Linux then?

Depends: between 253 K and 800K.
Title: Re: Linux binaries too big
Post by: tk on January 16, 2017, 03:11:25 pm
Depends: between 253 K and 800K.

Same lpi, same bitness, same compiler options, 253K a SO on Linux and 200K a DLL on Windows?
If yes then I don't believe you. Make a proof.
Title: Re: Linux binaries too big
Post by: Thaddy on January 16, 2017, 03:34:01 pm
Make a proof.
I interpreted it differently - I tested one simple and one complex shared lib - but this should be around 250k on arm-linux. On Windows and 32bit intel  linux it is much smaller:
Code: [Select]
library simple;
{$CALLING C}
uses initc; // this is actually needed for an so to make it callable from other languages.

function AddMe(const a,b:integer):integer;
begin
  AddMe := a+b;
end;

exports AddMe;
begin
end.

Ps. the .o for this is just 2667 bytes on arm.
Title: Re: Linux binaries too big
Post by: tk on January 16, 2017, 04:29:43 pm
I interpreted it differently

Let's stay on i386 for simplicity. Tried your small lib now on Win,Linux,OS X. Results attached. Still Linux binary has the biggest size (dll is even 5 times smaller than so).
.o files are completely different matter I think, their sizes are similar.

However, these small libs are not representative enough for the problem described in my first post.
Because IMO here the binary file overhead and/or RTL differences clearly win against the size of compiled user code.
Title: Re: Linux binaries too big
Post by: Fred vS on January 16, 2017, 05:15:45 pm
Hello.

The size of fpc libraries are too big because dynamic runtime packages are not supported yet.

But it is WIP.

http://free-pascal-general.1045716.n5.nabble.com/Size-of-program-vs-library-td5718200.html (http://free-pascal-general.1045716.n5.nabble.com/Size-of-program-vs-library-td5718200.html)

Fre;D
Title: Re: Linux binaries too big
Post by: Thaddy on January 16, 2017, 06:06:39 pm
Yes. But that is a one time penalty,about 200K-250K, and the size should not grow significantly in size compared to a dll except for that 200K-250K penalty that is the runtime lib.
That means the sizes should converge to a similar size with larger dynlibs. And that is what I see.
Title: Re: Linux binaries too big
Post by: tk on January 16, 2017, 07:44:27 pm
That means the sizes should converge to a similar size with larger dynlibs. And that is what I see.

Unfortunatelly that is what I don't see.

EDIT: Finally I solved this by adding -k--gc-sections to compiler options. Now the linux builds have similar size as OSX dylibs, which is ca 1.4x the size of Windows DLLs. And the Linux build map file finally shows the removed sections. I don't know why, because I have -XX option checked, but it works.
Title: Re: [SOLVED] Linux binaries too big
Post by: Jonas Maebe on February 11, 2017, 08:01:15 pm
If you compile with the -Cn command line parameter, you should be able to see which parameters FPC is passing to ld by looking at the generated ppas.sh file.
Title: Re: [SOLVED] Linux binaries too big
Post by: SymbolicFrank on February 11, 2017, 08:59:47 pm
I want my executable to include anything it might even remotely need. Because I want it to run on all the different versions.

It's called "dll hell", although they could be called .so or whatever instead.

If you want tiny, you also want endless dependencies.
TinyPortal © 2005-2018