Search topics...
Build SystemsSections & Memory Layoutfoundational

Static library (.a) vs relocatable object (.o) vs shared library (.so) — when does each apply in embedded?

0 upvotes
Practice with AISoon
Study the fundamentals first — Build Systems topic page

Three different things at the binary level:

.o — Relocatable object file. The output of compiling and assembling one source file. Contains compiled code, data, a symbol table, and relocation entries. Not yet linked, no final addresses. The linker takes one or more .o files (plus libraries) and produces an executable. Per-source compilation produces .o; almost every build goes through .o files as the intermediate step.

.a — Static library (archive). A collection of .o files bundled together with an index. When you pass -lfoo, the linker searches for libfoo.a and pulls in only the .o members that satisfy unresolved symbols — selectively, not the whole archive. Used everywhere in embedded: libc.a, libm.a, libgcc.a, vendor SDK static libs. The result is statically linked into the final ELF; no runtime dependency.

.so (or .dll) — Shared library. Dynamically linked at runtime. The executable contains references to symbols, and the OS loader resolves them against the shared library when the program starts. Almost never used in bare-metal embedded because there's no OS loader. Common on embedded Linux for the same reasons as desktop Linux: less duplication, easier patches, smaller per-application footprint. But on a Cortex-M MCU running bare metal or RTOS, you statically link everything into one ELF.

So for an MCU embedded engineer: .o is the per-file unit, .a is the way you bundle libraries (vendor SDKs, libc, third-party drivers), .so is something you'd see only if you drift into embedded Linux. Linker errors like "cannot find -lc" mean a .a (static library) is missing from the link command.

Source: Build Systems Q&A