Duplicate symbol 'foo' error after GCC 10 default changes to -fno-common
0 reputation · 04 Jul 2024, 20:33 UTC
0 reputation · 04 Jul 2024, 20:33 UTC
When compiling two translation units that each contain a tentative definition of a global variable named foo, GCC 10 and newer emit a linker error such as duplicate symbol 'foo'. The error arises because the compiler now treats tentative definitions as strong, not common, symbols.
Prior to GCC 10, the compiler defaulted to -fcommon, merging such symbols. The change to -fno-common has caused widespread build failures in legacy codebases that rely on the old default. The GCC development community has debated whether to revert this default, but no definitive decision has been made and it remains a documented open question.
What is the current status of the default behavior for tentative definitions in upcoming GCC releases? Will future versions restore -fcommon or continue with -fno-common? Which migration strategy should projects adopt to maintain portability across GCC versions?
Starting with GCC 10, the compiler changed the default handling of tentative definitions from -fcommon to -fno-common. This makes each tentative definition a strong symbol, so when two translation units contain a tentative definition of the same global variable (e.g., foo) the linker reports a duplicate‑symbol error. GCC 11, 12, 13, and the released GCC 14 series have retained -fno-common as the default; there has been no official announcement to revert to -fcommon.
If you are seeing duplicate symbol 'foo' with GCC ≥10, the cause is the stricter default. The linker error will disappear if either the compilation is forced to use -fcommon (restoring the old merging behavior) or the source is changed so that only one translation unit provides a definition while the others declare it extern.
gcc --version. If it is 10 or newer, the default is -fno-common.foo a single definition.
int foo = 0; (or appropriate initializer) and in all other files declare extern int foo;. Rebuild; the error should vanish without any extra flags.-fcommon to the compile command for all translation units (e.g., CFLAGS += -fcommon in a Makefile) or adjust your build system to pass this flag globally. This restores the pre‑GCC 10 merging behavior.# Example Makefile snippet
ifeq ($(findstring 10,$(shell gcc -dumpversion)),)
# GCC <10 already defaults to -fcommon; keep it explicit
CFLAGS += -fcommon
else
# GCC ≥10 needs -fcommon to regain the old behavior
CFLAGS += -fcommon
endif
(Replace the condition with a proper version test if needed.)
nm -C *.o or objdump -t *.o to confirm that foo now has a single strong symbol (type D or B) or, when using -fcommon, a common symbol (type C) that the linker merges.Please let me know if you are able to modify the source code to provide a single definition for foo. Your answer will determine whether the source‑change route or the -fcommon flag is the recommended path.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.