Reduce binary size

I’m rewriting vulkan tutorial in zig. Is there a way to reduce binary size in the new version 0.16?

zig-x86_64-linux-0.15.2/zig build-exe   -OReleaseSmall \
        -fstrip \
        -fno-unwind-tables \
        -fsingle-threaded \
        -dynamic \
        -lglfw -lvulkan -lc main.zig

16K     main

zig version 0.16 and same options - 112K main

Also that happens with C++ from tutorial

zig-x86_64-linux-0.15.2/zig c++ main.cpp \
        -Oz \
        -lglfw -lvulkan -lstdc++ -o main

372K    main

zig build-exe main.cpp -OReleaseSmall \ -- 0.16
      -fstrip \
        -lglfw -lvulkan -lstdc++

288K

With 0.12: main 256K. It doesn’t matter whether you use zig c++ or zig build-exe.

zig-linux-x86_64-0.12.0/zig build-exe main.cpp -OReleaseSmall \
      -fstrip \
        -lglfw -lvulkan -lstdc++

zig-linux-x86_64-0.12.0/zig c++ main.cpp \
        -Oz \
        -lglfw -lvulkan -lstdc++ -o main

clang++ -lvulkan -lglfw -std=c++20 main.cpp -o main.out
 
20K main.out

Am I missing some options or is it something else? I’m a newbie

This is a known disadvantage to the new std.Io I suspect. Basically the way the new IO system is written in the standard library, it’s far harder for the compiler to be sure about which IO functions are not being used. So it’s including a bunch of functions “just in case”. [1]

There are plans afoot to give the compiler more information about what is unused so it can strip that code out again. So, hopefully, this is a temporary regression.

Edit: Tracked by https://codeberg.org/ziglang/zig/issues/31421


  1. Slightly longer version: As std.Io is a table of function pointers to all IO functions, using std.Io means a pointer exists to every function. Therefore they are “used” and have to be included in the binary, even if those pointers are never dereferenced by your code. ↩︎

2 Likes

Thank you!
And std.Io zig is including for c++?

I was just commenting on the Zig version. What might be going on with the C++ version… I don’t know.

1 Like

I think the difference in size between zig c++ and clang is because zig will link libc++ statically into your binary. Where as clang will dynamically link it to your system’s libc++.

You can confirm this by running ldd against the binaries they produce. For me it looks like this for a c++ hello world:

# zig c++ compiled:
$ ldd zig_a.out
	linux-vdso.so.1 (0x00007ffe45174000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007c1d0c800000)
	/lib64/ld-linux-x86-64.so.2 (0x00007c1d0ca41000)
# G++ compiled:
~ $ ldd gcc_a.out
	linux-vdso.so.1 (0x00007ffdc2524000)
	libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x0000792a20200000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x0000792a20625000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x0000792a1fe00000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x0000792a2053c000)
	/lib64/ld-linux-x86-64.so.2 (0x0000792a20680000)

All that extra code that is linked to the system for the clang build has to be included into the binary itself for the zig build, hence why it’s bigger.

objdump is also a nice utility to investigate binary bloat. It will show a bunch of c++ panic handlers, etc. in the zig binary that are missing from the gcc/clang binary. If std.Io was included in your binary, you would see a bunch of symbols called Io.Threaded.... But they shouldn’t be there for a zig c++ binary.

2 Likes

I’m not sure about standard lib, clang linking to libstdc++.

zig-linux-x86_64-0.12.0/zig c++ main.cpp \
        -Os \
        -l:libstdc++.so.6 -l:libgcc_s.so.1 \
        -lvulkan -lglfw \
        -fno-rtti \
        -fno-asynchronous-unwind-tables \
        -fno-unwind-tables \
        -fno-threadsafe-statics \
        -fno-use-cxa-atexit \
        -fno-stack-protector \
        -ffunction-sections -fdata-sections \
        -Wl,--gc-sections  \
        -o main_zig_diag
148K

Ldd same
Without linking to libstdc++ - 232K
Compiling with g++ - 48K

Yeah, you’ve dynamically linked it, but I don’t think that stopped it statically linking, too.

This issue looks related. https://codeberg.org/ziglang/zig/issues/31781

1 Like

That’s why this options doesn’t work:
-nostdinc++ (Cannot link to my stdlib)
-stdlib=libc++ (Unused no matter what i do)