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.