This weekend I spent some time thinking that (Golang built) binaries of dpcmder are a bit too huge for my taste. Some would say that ~10 megs is not so much for today's world but ~10 megabytes seemed to me to be too much so I set out on a mission to find out if I can trim dpcmder size a bit.
After some googling, I found this nice "shrink your go binaries" blog which explains exactly what I needed to do to achieve my goal.
It boils down to one change in the current build process (remove debugging info & system table) and one additional step after the build (compress binaries).
Removing debugging info & system table
Instead of using default go build command, for example:
GOOS=linux GOARCH=amd64 go build -o release/dpcmder-linux-amd64 dpcmder.go
You have to add additional ldflags to instruct the linker to remove all debugging info (-w) & symbol table (-s):
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o release/dpcmder-linux-amd64 dpcmder.go
Actually, this research of ldflags brought me to one other issue on my dpcmder todo list - adding application version for each release. This caused me to use one more ldflag (-X) to change values of version variables:
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w -X 'github.com/croz-ltd/dpcmder/help.Version=$(git tag | tail -n1)' -X 'github.com/croz-ltd/dpcmder/help.Platform=linux/amd64' -X 'github.com/croz-ltd/dpcmder/help.BuildTime=$(git tag | tail -n1).$(date -u -Iseconds)'" -o release/dpcmder-linux-amd64 dpcmder.go
Compressing binaries
UPX is a free, portable, extendable, high-performance executable packer for several executable formats.
After installing UPX it is easy to use it and for the best compression results I added the flag "--brute" mentioned in the blog above:
upx --brute release/*
$ upx --brute release/*
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2013
UPX 3.91 Markus Oberhumer, Laszlo Molnar & John Reiser Sep 30th 2013
File size Ratio Format Name
-------------------- ------ ----------- -----------
7925760 -> 2538980 32.03% linux/elf386 dpcmder-linux-386
9105408 -> 2686192 29.50% linux/ElfAMD dpcmder-linux-amd64
8421068 -> 2772992 32.93% Mach/i386 dpcmder-mac-386
9653400 -> 2785280 28.85% Mach/AMD64 dpcmder-mac-amd64
7698432 -> 2449408 31.82% win32/pe dpcmder-win-386.exe
8865792 -> 2597376 29.30% win64/pe dpcmder-win-amd64.exe
-------------------- ------ ----------- -----------
51669860 -> 15830228 30.64% [ 6 files ]
Packed 6 files.
This step took quite a long time to complete but results were worth waiting. As you can see below from binary files update times, some binaries were compressed faster and some were compressed slower (compression of win/386 binaries lasted almost 30 minutes while compression of Linux binaries lasted for around 3 minutes).
$ stat -c "%.19z %n" release/*
2020-01-13 10:23:02 release/dpcmder-linux-386
2020-01-13 10:26:57 release/dpcmder-linux-amd64
2020-01-13 10:29:52 release/dpcmder-mac-386
2020-01-13 10:36:54 release/dpcmder-mac-amd64
2020-01-13 11:03:45 release/dpcmder-win-386.exe
2020-01-13 11:10:54 release/dpcmder-win-amd64.exe
Note that these 6 binaries could be compressed in parallel to achieve much better times on the modern-day multi-core machines.
How much did we trimmed?
After the whole process, all 6 binaries are now much smaller. The total size of all binaries shrank from the original 65M to a more acceptable 16M. Sizes for all 6 binaries are given below.
default go build without any -ldflags
$ ls -sh1 release/
total 65M
11M dpcmder-linux-386
12M dpcmder-linux-amd64
11M dpcmder-mac-386
12M dpcmder-mac-amd64
11M dpcmder-win-386.exe
12M dpcmder-win-amd64.exe
go build with -ldflags="-s -w"
$ ls -sh1 release/
total 50M
7,6M dpcmder-linux-386
8,7M dpcmder-linux-amd64
8,1M dpcmder-mac-386
9,3M dpcmder-mac-amd64
7,4M dpcmder-win-386.exe
8,5M dpcmder-win-amd64.exe
result of running UPX on go build (with -ldflags="-s -w")
$ ls -sh1 release/
total 16M
2,5M dpcmder-linux-386
2,6M dpcmder-linux-amd64
2,7M dpcmder-mac-386
2,7M dpcmder-mac-amd64
2,4M dpcmder-win-386.exe
2,5M dpcmder-win-amd64.exe
After comparing the latest dpcmder release assets sizes to the previous dpcmder release asset sizes I must conclude that my mission from the start of this blog is successfully accomplished :)
Top comments (0)