Skip to content
Latchkey

ld "multiple definition of" - One Definition Rule Violations

The linker found the same symbol defined in more than one object file. A function or variable was defined (not just declared) in a header, or a global lives in two translation units - a One Definition Rule violation.

What this error means

Every object compiles, then the link fails with "multiple definition of <symbol>; first defined here". It often appears after a refactor that moved a definition into a header, or under GCC 10+ which defaults to -fno-common.

ld output
/usr/bin/ld: b.o:(.bss+0x0): multiple definition of `g_counter'; a.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status

Common causes

A definition placed in a header

A non-inline function or a non-inline/non-const global variable defined in a header is compiled into every .cpp that includes it, so the linker sees it defined many times.

GCC 10+ -fno-common tentative definitions

A global declared without extern in a header (a tentative definition) used to be merged under the old common model. GCC 10 defaults to -fno-common, so each unit now defines it and the link clashes.

How to fix it

Declare in the header, define once

Keep only an extern declaration in the header and put the single definition in one .cpp.

C++
// counter.h
extern int g_counter;
// counter.cpp
int g_counter = 0;

Mark header definitions inline

  1. For functions/variables that must live in a header, mark them inline (C++17 inline variables) so duplicate definitions are merged.
  2. For globals, use extern in the header and define in exactly one source file.
  3. Do not retry - this is a source/ODR error, not transient.

How to prevent it

  • Put declarations in headers and definitions in a single .cpp.
  • Use inline for header-only functions and variables.
  • Build with -fno-common locally so ODR clashes surface before CI.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →