Notes on migrating from GCC 4.8 to 4.9
I recently migrated a firmware from building with GCC 4.8 to 4.9. Here are some notes about a few areas that tripped me up. The result is quite good: the firmware builds faster, is 20 percent smaller (which is very important in our use case) and we get the benefit of GCC 4.9 features like the improved analyzer, color output, and more aggressive optimizations.
All of these (with the exception of color output) apply to at least GCC 4.8 as well so I was able to use the same Makefile without checking for toolchain versions.
Making static libraries
I was making static libraries like this:
foo.a: $(OBJS)
$(AR) rcs $@ $^
With GCC 4.9 this results in an archive that has no usable index so you’ll see
every symbol missing when you try to link against it. Furthermore there are
now gcc-
wrappers for ar
, nm
, and ranlib
which enable GCC’s new plugin
architecture. I therefore changed those definitions:
AR := $(CROSS_COMPILE)gcc-ar
NM := $(CROSS_COMPILE)gcc-nm
RANLIB := $(CROSS_COMPILE)gcc-ranlib
and then made static libraries like this:
foo.a: $(OBJS)
$(AR) rcs $@ $^
$(RANLIB) $@
I also use link time optimization (LTO) and for that, we need to tell GCC to
not make “thin” objects, -flto
becomes:
-flto -ffunction-sections
That should be used consistently when linking, so make sure you revisit how you finally link your ELF, not just libraries that it depends on.
Overly aggressive optimizations
I found that GCC 4.9 removed a symbol that I do reference. When this happens,
consider using the used
attribute to tell the compiler and linker not to do
that. In my case it was the FreeRTOS function vTaskSwitchContext
so I added
the following to FreeRTOSConfig.h:
void __attribute__((used)) vTaskSwitchContext(void);
Colors
I like GCC’s color coded output. You can tell GCC to always colorize by adding:
-fdiagnostics-color=always
That made warnings and errors a lot easier to read.
Assembly labels
I hit an issue with local labels and the assembler when using LTO and some
third-party code – this person’s issue and solution are basically the same. Replace your explicit labels with automatic ones, so for example use label 0
and then go back to 0
with 0b
or forward with 0f
. The
toolchain will then do the right thing.
Side notes
GCC version in Makefile
You should not need to know what version of GCC is used in a Makefile, however if for some reason you did need it, here’s one way to do it:
GCC_VERSION := $(shell $(CC) --version | grep ^gcc | sed 's/^.* //g')
GCC_V_MAJOR := $(word 1, $(subst ., ,$(GCC_VERSION)))
GCC_V_MINOR := $(word 2, $(subst ., ,$(GCC_VERSION)))
GCC_V_PATCH := $(word 3, $(subst ., ,$(GCC_VERSION)))
You can then compare (as strings) the version itself or just the major, minor, and patch level. Make only deals with strings so any numerical checks would need to be called out to the shell. If you find yourself going this route, it’s time to consider using automake or a similar higher-level configuration system and then generating your Makefiles from that. You can then take advantage of gcc’s feature test and predefined macros. The above may still be useful for one or two minor fixups while keeping a basic Makefile.