CONCEPT Cited by 1 source
ODR violation (One-Definition Rule)¶
Definition¶
The One-Definition Rule (ODR) is a C++ language rule that requires every non-inline external symbol (function, variable, class type, enum) to have exactly one definition across the entire program. The linker enforces this — when two definitions of the same mangled symbol appear in the linked object files, the link fails with "duplicate symbol" errors.
An ODR violation occurs whenever that invariant is broken. Typical causes:
- Two translation units define the same symbol.
- A header defines a symbol non-inline and is included in multiple
.cppfiles. - Two versions of the same library are statically linked into the same binary — every symbol they share becomes a duplicate.
Why it matters for dual-stack migrations¶
The last case is the canonical motivating instance on this wiki. When an organization wants to A/B test two versions of a library in the same binary — a legacy fork and an upstream release — they cannot simply link both copies. The linker sees thousands of duplicate definitions (every namespaced class, free function, macro-expanded global) and refuses to produce an executable.
"However, this violates the C++ linker One Definition Rule (ODR), causing thousands of symbol collisions, so we turned to finding a way to make two versions of the same library coexist in the same address space." (sources/2026-04-09-meta-escaping-the-fork-webrtc-modernization)
Resolution strategies¶
- Symbol renamespacing —
automated rewrite of all namespaces in one copy to a
flavor-specific prefix (e.g.
webrtc::→webrtc_latest::/webrtc_legacy::). Every symbol becomes unique. This is the load-bearing mechanism in Meta's WebRTC shim. - Move non-namespaced globals into namespaces — global C functions, free variables, non-namespaced classes are rewritten to live inside a flavor-specific namespace, or given flavor-suffixed identifiers in-place.
- Share innocuous internal modules — some modules (e.g.
rtc_basein libwebrtc) are compatible enough between flavors that one shared copy is safe. Shrinks both the shim surface and the binary. - Resolve macro collisions — macros like
RTC_CHECK/RTC_LOGthat appear in multiple headers can redefine-error when both flavors' headers appear in the same translation unit. Fix by removing spurious includes, renaming rarely-used macros, or sharing the macro via a shared internal module. - Dynamic loading (alternative, not taken by Meta) — instead of static linking, load each copy as a separate shared library at runtime. Different address spaces, no ODR issue. Rejected in Meta's case due to "application build graph and size constraints."
Seen in¶
- sources/2026-04-09-meta-escaping-the-fork-webrtc-modernization
— canonical wiki instance. Thousands of ODR violations from
statically linking legacy + upstream WebRTC in the same binary;
resolved via scripted namespace rewriting, movement of globals
into namespaces, and shared
rtc_base.
Related¶
- concepts/symbol-renamespacing — the load-bearing resolution.
- concepts/shim-layer — the higher-level construct that sits on top of an ODR-resolved dual-stack binary.
- patterns/shim-for-dual-stack-ab-testing — the broader migration pattern this enables.