Christian Weisgerber:
> I'll send a followup message with additional background information.
So what's a "common (variable)"? When multiple object files have
an externally visible variable with the same name, the linker will
merge these variables so that they all refer to the same memory
location.
This is an ancient linker feature. It was never part of any C
language standard. In fact C is quite explicit that you can
only define a variable in one object file
int number;
and then have to declare it elsewhere:
extern int number;
A declaration makes a name and type known. A definition additionally
reserves memory for a variable (or creates code for a function).
One frequent way to end up with commons is to put a definition in
a header file that is included by multiple source files.
How to fix commons? The first step is to determine whether they
are intentional or whether they are an accidental name clash, a bug
in fact. Intentionally shared variables should just be defined in
one place and declared with "extern" elsewhere. Accidental ones
can either be renamed or their visibility limited to the same source
file by declaring them "static".
Both LLVM11 and GCC10 no longer permit commons by default. FreeBSD
has already switched to LLVM11 and quick-moving Linux distributions
are switching to GCC10.
To fix a port, in order of preference:
(1) Update to a newer release that is already fixed.
(2) Cherry-pick a fix from an upstream repository if not already
included in a newer release.
(3) Create a patch yourself, or copy one from FreeBSD etc., if
no upstream fix is available.
(4) Explicitly permit commons by adding -fcommon to CFLAGS if
the code base really depends on it.
How to reproduce build errors due to commons? Since we haven't
switched compilers yet, you can add -fno-common to CFLAGS. For
large scale work on this, it is easier to rebuild your compiler so
that it defaults to -fno-common. Below is a diff for our in-tree
clang:
Index: gnu/llvm/clang/include/clang/Driver/Options.td
===================================================================
RCS file: /cvs/src/gnu/llvm/clang/include/clang/Driver/Options.td,v
retrieving revision 1.3
diff -u -p -r1.3 Options.td
--- gnu/llvm/clang/include/clang/Driver/Options.td 1 Dec 2020 13:30:13
-0000 1.3
+++ gnu/llvm/clang/include/clang/Driver/Options.td 26 Jan 2021 21:09:47
-0000
@@ -840,7 +840,8 @@ def fno_record_command_line : Flag<["-"]
Group<f_clang_Group>;
def : Flag<["-"], "frecord-gcc-switches">, Alias<frecord_command_line>;
def : Flag<["-"], "fno-record-gcc-switches">, Alias<fno_record_command_line>;
-def fcommon : Flag<["-"], "fcommon">, Group<f_Group>;
+def fcommon : Flag<["-"], "fcommon">, Group<f_Group>,
+ Flags<[CoreOption, CC1Option]>, HelpText<"Place uninitialized global
variables in a common block">;
def fcompile_resource_EQ : Joined<["-"], "fcompile-resource=">, Group<f_Group>;
def fcomplete_member_pointers : Flag<["-"], "fcomplete-member-pointers">,
Group<f_clang_Group>,
Flags<[CoreOption, CC1Option]>,
Index: gnu/llvm/clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
RCS file: /cvs/src/gnu/llvm/clang/lib/Driver/ToolChains/Clang.cpp,v
retrieving revision 1.3
diff -u -p -r1.3 Clang.cpp
--- gnu/llvm/clang/lib/Driver/ToolChains/Clang.cpp 1 Dec 2020 13:30:13
-0000 1.3
+++ gnu/llvm/clang/lib/Driver/ToolChains/Clang.cpp 26 Jan 2021 21:09:47
-0000
@@ -1404,20 +1404,6 @@ static bool isSignedCharDefault(const ll
}
}
-static bool isNoCommonDefault(const llvm::Triple &Triple) {
- switch (Triple.getArch()) {
- default:
- if (Triple.isOSFuchsia())
- return true;
- return false;
-
- case llvm::Triple::xcore:
- case llvm::Triple::wasm32:
- case llvm::Triple::wasm64:
- return true;
- }
-}
-
static bool hasMultipleInvocations(const llvm::Triple &Triple,
const ArgList &Args) {
// Supported only on Darwin where we invoke the compiler multiple times
@@ -5638,11 +5624,9 @@ void Clang::ConstructJob(Compilation &C,
if (!Args.hasFlag(options::OPT_Qy, options::OPT_Qn, true))
CmdArgs.push_back("-Qn");
- // -fcommon is the default unless compiling kernel code or the target says so
- bool NoCommonDefault = KernelOrKext || isNoCommonDefault(RawTriple);
- if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common,
- !NoCommonDefault))
- CmdArgs.push_back("-fno-common");
+ // -fno-common is the default, set -fcommon only when that flag is set.
+ if (Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common, false))
+ CmdArgs.push_back("-fcommon");
// -fsigned-bitfields is default, and clang doesn't yet support
// -funsigned-bitfields.
Index: gnu/llvm/clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
RCS file: /cvs/src/gnu/llvm/clang/lib/Frontend/CompilerInvocation.cpp,v
retrieving revision 1.2
diff -u -p -r1.2 CompilerInvocation.cpp
--- gnu/llvm/clang/lib/Frontend/CompilerInvocation.cpp 10 Sep 2020 20:28:14
-0000 1.2
+++ gnu/llvm/clang/lib/Frontend/CompilerInvocation.cpp 26 Jan 2021 21:09:47
-0000
@@ -808,7 +808,7 @@ static bool ParseCodeGenArgs(CodeGenOpti
Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags);
Opts.RecordCommandLine = Args.getLastArgValue(OPT_record_command_line);
Opts.MergeAllConstants = Args.hasArg(OPT_fmerge_all_constants);
- Opts.NoCommon = Args.hasArg(OPT_fno_common);
+ Opts.NoCommon = !Args.hasArg(OPT_fcommon);
Opts.NoInlineLineTables = Args.hasArg(OPT_gno_inline_line_tables);
Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float);
Opts.OptimizeSize = getOptimizationLevelSize(Args);
--
Christian "naddy" Weisgerber [email protected]