In short, disabling link-time optimisation and enabling dead-code stripping can yield smaller binaries.
my binary is 64Mb instead of about 20Mb.
Where does the second number come from? Is that from a plain release build?
If you’re using the juce_recommended_* targets to supply compiler flags, be aware that some options are only enabled in Release mode, i.e. -flto and -O3 are only passed for Release, but not RelWithDebInfo. I recommend building with --verbose and checking over the commandlines that are generated for RelWithDebInfo builds to check that you’re using the expected optimisation level and other settings.
Yeah, the smaller number is the normal Release build. I’ve set -O3 for RelWithDebInfo. Slightly more confused about the lto settings - looking into it.
Ideally I think I’m going to come at it from the other end by using Release and adding the debug info to it with -g. But struggling to make it make all the right output for dsymutil:
dsymutil /Users/jim/Code/multiband/cmake.build/MultibandX6_artefacts/Release/VST3/Multiband\ X6.vst3/Contents/MacOS/Multiband\ X6 -o ~/Symbols/MultibandX6_VST3_1.0.33.dSYM
warning: (x86_64) /tmp/lto.o unable to open object file: No such file or directory
warning: (arm64) /tmp/lto.o unable to open object file: No such file or directory
Ok, so to get symbols available for dsymutil someone worked out that the solution is: -Wl,-object_path_lto,lto.o
on macOS, the full debug info is never stored in the executable. It is either left in the object files, and the executable just keeps a record of the paths to the object files, or it is put into a “dSYM bundle”.
when compiling and linking in a single step with the clang/clang++ drivers and the -g flag, i.e.
the driver automatically calls dsymutil at the end of the process to create this dSYM bundle. (this can be seen by adding -v to tell the driver to output all commands it issues.)
when compiling and linking in separate steps, which is usually the case with Make- or Automake- based build systems, the driver does not call dsymutil, so the debug info is left in the object files.
When compiling and linking in a single step with -flto, the driver calls the linker with the -object_path_lto flag and a path in $TMPDIR, eg. -object_path_lto /var/folders/lr/r6n2057j0dzd4gdb614fp0740000gp/T/cc-ac0bf8.o.
when compiling and linking in separate steps, the driver does not add this option to the linker call.
man ld reveals that if object_path_lto is not used, the linker deletes the temporary file used for link time optimization after the linking step is finished.
The last point means that the final executable keeps a reference to this deleted temporary file (I guess /tmp/lto.o is hardcoded in ld64’s source code, I did not check that). So when the executable is loaded in GDB, the debugger tries to load the debugging symbols from the now deleted temporary file.
Adding -Wl,object_path_lto,lto.o to the linking command (in a Makefile for example) leaves the object file used for link time optimization (here lto.o) in the build directory, which allows to debug the executable. It also allows calling dsymutil manually to create the dSYM bundle.