Prefer gcc-ar to ar In Your Buildsystems

While working on our Creating a Cross-Platform Build System for Embedded Projects using Meson course, I fell into a rabbit hole while writing the lesson on link-time optimization (LTO).

I enabled LTO support using Meson’s built-in option:

meson buildresults -Db_lto=true

Everything worked just fine with the native toolchain setup.

Next, I tested LTO support with cross-compilation:

meson buildresults -Db_lto=true --cross-file=build/cross/arm.txt --cross-file=build/cross/cortex-m4_hardfloat.txt

Our cross-compilation rules use the gnu-arm-none-eabi toolchain:

[binaries]
c = 'arm-none-eabi-gcc'
cpp = 'arm-none-eabi-c++'
ar = 'arm-none-eabi-ar'
strip = 'arm-none-eabi-strip'

When I ran the build, I was surprised to receive a flood of warnings from arm-none-eabi-ar:

arm-none-eabi-ar: src/25a6634@@c@sta/stdlib_imaxabs.c.o: plugin needed to handle lto object
arm-none-eabi-ar: src/25a6634@@c@sta/stdlib_imaxdiv.c.o: plugin needed to handle lto object
arm-none-eabi-ar: src/25a6634@@c@sta/stdlib_labs.c.o: plugin needed to handle lto object
arm-none-eabi-ar: src/25a6634@@c@sta/stdlib_ldiv.c.o: plugin needed to handle lto object

I researched the problem and found multiple recommendations to add a --plugin argument to the arm-none-eabi-ar call to fix the problem:

--plugin=$(arm-none-eabi-gcc --print-file-name=liblto_plugin.so)

I tested this approach by manually adding the argument to the generated -ar command, and it did address the problem. However, I just couldn’t believe this was actually the solution. It’s such a hacky flag to add, there’s no way everyone is doing this when they’re using LTO.

I did a bit more research, and this Stack Overflow thread keyed me into the solution: use arm-none-eabi-gcc-ar instead of arm-none-eabi-ar. The *-gcc-ar variant is a wrapper for *-ar that provides the plugin argument(s) we need.

gcc-ar ... => ar --plugin=/path/to/liblto_plugin.so ...

Once I switched my toolchain to use *-gcc-ar, the warnings vanished.

[binaries]
c = 'arm-none-eabi-gcc'
cpp = 'arm-none-eabi-c++'
# *-gcc-ar is used over *-ar to support LTO flags. 
# Without -gcc-ar, LTO will generate a linker warning:
# arm-none-eabi-ar: file.o: plugin needed to handle lto object
ar = 'arm-none-eabi-gcc-ar'
strip = 'arm-none-eabi-strip'

My conclusion is that we should prefer gcc-ar over ar by default in our build systems. This way, we can support LTO as an option for our projects.

It is also worth noting that both nm and ranlib have gcc-nm and gcc-ranlib equivalents which provide the proper LTO plugin arguments. They should be used whenever you are working with LTO files.

Share Your Thoughts

This site uses Akismet to reduce spam. Learn how your comment data is processed.