How do you debug a "multiple definition" or "undefined reference" linker error?
0 upvotes
Practice with AISoon
Both are about cross-file consistency, but they have different fixes.
undefined reference to 'foo' — the linker couldn't find a definition for foo in any of the .o files or libraries you linked. Common causes:
- Missing library. For
printfand friends, make sure libc is being linked — check for--specs=nano.specsor explicit-lcin the link command. Vendor SDKs often need explicit-lvendor_lib. - Source file not in the build. The file containing
foo's definition isn't being compiled, so no.oexists with the symbol. Check the build system's source list. - Wrong symbol name (C/C++ boundary). C++ does name mangling. If a C++ caller references a C function declared without
extern "C", the C++ side calls_Z3foov(mangled) but the C definition providesfoo(unmangled). Wrap the declaration inextern "C" { ... }. - Typo or wrong prototype. Check spelling and signature.
Diagnostic: arm-none-eabi-nm on each candidate .o shows whether foo is defined (T) or only referenced (U).
multiple definition of 'foo' — the same symbol is defined in two .o files. Common causes:
- Non-static function or global in a header. Every
.cthat includes the header gets its own copy. Fix: mark itstatic inline(per-TU copy is allowed) or move the body to a single.cfile with only a declaration in the header. - A
.cfile is being compiled and linked twice. Check the source list for duplicates. - Two libraries provide the same symbol. Less common; usually the fix is to remove one or use
--allow-multiple-definition(not recommended — usually masks a real problem).
Diagnostic: arm-none-eabi-nm on each .o to find where the symbol is defined.
The general workflow: run the build, copy the failing symbol name, run nm on every .o in the link to see who defines it (or doesn't). Both errors are 1-minute fixes once you know which .o is at fault.
Source: Build Systems Q&A
