Description
What we have
With CMake we have 3 build options provided by Cmake:
Release
, builds with-O3
, doesn't feature any debug symbolRelWithDebInfo
, builds with-O2
, features debug symbolsDebug
, builds without-O
, features debug symboles
Well, there are more like MinSizeRel
but we never used that and I never used that for Unvanquished, so I won't mention it.
Alongside that we provide the USE_DEBUG_OPTIMIZE
variable that enables -Og
. The big difference with RelWithDebInfo
and Debug
with USE_DEBUG_OPTIMIZE
is that the later still enables assertions.
With build with RelWithDebInfo
because we want to ship debug symbols because of breakpad. But then it means we build release builds with -O2
, I see no reason to not use -O3
. We also enable LTO in releases and uses -ffast-math
by default.
My experience
On my end here when debugging/testing/profiling I use all those build options for various purpose :
Debug
, rare, usually by mistake, or when I want to really step line by line in a debugger.Debug
withUSE_DEBUG_OPTIMIZE
, the profile I use the most: keeps assertions enabled, keeps debug symbols, and optimizations are good enough for profiling to be meaningful (unlikeDebug
), sometime enabling LTO, sometime not (mostly to reduce link time, sometime to better step the code)RelWithDebInfo
: less used, when I want to look at something release-like, usually used with LTO enabled.Release
, when I want to benchmark what can do our engine in the better options possible, usually combined with-march=native
, LTO enabled and even using some vendor-specific compiler.
About LTO
about LTO, it is really a big deal, for sure it changes a lot the shape of the code between the source and the produced binary, but the benefits are so strong I will not defend the removal of it.
- With our architecture of shipping framework libraries in engine repository for the game, our only change of optimizing them is to use LTO.
- LTO reduces the binary size in a very impressive manner!
Here are some binary size comparison (daemon
client) with different build profiles (RelWithDebInfo
not being stripped):
build profile | binary size |
---|---|
RelWithDebInfo | 63187776 |
RelWithDebInfo LTO | 39726360 |
Release | 4205624 |
Release LTO | 3379952 |
MinSizeRel | 2939960 |
MinSizeRel LTO | 2464800 |
We enabled LTO in release builds 4 years ago in September of 2020: 2db798d .
We already released Unvanquished 0.52
, 0.52.1
, 0.53
, 0.53.1
, 0.53.2
, 0.54
and 0.54.1
with LTO, without problems.
About -O3
I see no reason to not enable -O3
in release builds.
I also have some pikachu defense for enabling it, this is still pikachu defense but it is not that invalid in such context:
- Being concerned that
-O3
may not keep the expected program behaviour would face cognitive dissociation with enabling-ffast-math
by default. - Being concerned that
-O3
may make debugging harder would face cognitive dissociation with enabling LTO in releases.
About testing -O3
Except Debug
profile without optimization, I use intensively all named build profiles, so I use intensively -O3
and never experienced something bad caused by it. I consider -O3
well tested.
Where to enable -O3
?
I see no compelling reasons to not use -O3
in our release builds. Now one question may surface:
- Should we enable
-O3
in our CMake file for allRelWithDebInfo
builds. - Should we only do that in release scripts?
I'm in favor of the first option: people should debug what we release.