GCC LTO: Uncertain handling of -fcommon vs -fno-common during linking
0 reputation · 23 Mar 2025, 19:33 UTC
0 reputation · 23 Mar 2025, 19:33 UTC
When compiling with -flto and -fcommon, GCC often succeeds linking multiple source files that each declare a tentative global variable. Switching to -fno-common triggers duplicate symbol errors during the LTO phase, even though standard linking without LTO honours the flags consistently.
The GCC manual does not explicitly state whether -fcommon should be treated as a weak symbol during LTO, and empirical tests show that the behavior appears to vary across GCC 11, 12, and 13. This leaves developers unsure whether to depend on -fcommon when building shared libraries or static binaries that use LTO.
-fcommon as weak during LTO a documented GCC design choice, or an implementation quirk?-fcommon in LTO, and if so, how?-fcommon for tentative definitions when using LTO, or is a different strategy recommended?32275 reputation · 24 Mar 2025, 00:00 UTC
-fcommon is not a documented weak-symbol mechanism in GCC, and LTO does not change that contract. It emits mergeable ELF common symbols for tentative C definitions; -fno-common emits ordinary strong definitions. When two translation units contain int g; and are compiled with -fno-common, the linker sees two strong definitions and reports duplicates. The behavior is governed by ELF symbol resolution and the flags used on every object, not by an LTO-specific weak promotion.
-fcommon to -fno-common. Later releases inherit that default unless overridden.-fcommon, uninitialized file-scope variables become STT_COMMON symbols that the linker can merge. Under -fno-common, they become allocated .bss definitions.The errors you see are most likely caused by one of two conditions: (1) every object was compiled with -fno-common, so multiple tentative definitions are now strong and collide; or (2) objects were compiled with different settings, so some carry common symbols and others carry strong definitions. A non-LTO link can succeed while the LTO link fails if the LTO link sees a different set of objects or flags, because LTO re-examines the full symbol table. Treat version-specific differences between GCC 11, 12, and 13 as unverified until reproduced with your exact toolchain.
-fcommon or -fno-common flag. Do not mix.gcc -Q --help=common | grep -E -- '-f(no-)?common'
readelf -sW a.o b.o
Expect COM/STT_COMMON entries under -fcommon and .bss object definitions under -fno-common.extern in a header and define it in exactly one .c file. In C++, prefer a single definition or an inline variable.Capture the exact LTO link command and run readelf -s on one failing object. If any object used a different -fcommon setting, fix flag uniformity first. If all objects share the same setting and still fail, the source layout is the problem and you should move to the single-definition pattern.
Do not treat common symbols as a portable substitute for weak symbols, version scripts, or visibility controls in shared libraries. Common-symbol merging is ELF-specific and does not provide the override semantics of a weak definition. For new code, the single-definition-plus-extern strategy is the portable choice regardless of LTO.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.