We now build DB2 on linux ppcle with the IBM xlC 13.1.2 compiler. This version of the compiler is a hybrid compared to any previous compilers, retaining the IBM xlC backend for power, but using the clang front end. Because of this we are exposed to a large number of warnings that we don’t see with many other compilers (well we probably do for our MacOSX port, but we do not really have active development on that platform at the moment), and I’ve been trying to take down those counts to manageable levels. Header files that produce warnings have been my first target since they introduce the most repeated noise.

One message that I was seeing hundreds of was

[sourcecode language=”bash”]
warning: ‘extern’ variable has an initializer [-Wextern-initializer]
[/sourcecode]

This seemed to be coming from headers that did something like:

[sourcecode language=”cpp”]
#if defined FOO_INITIALIZE_IT_IN_SOME_SOURCE_FILE
extern const TYPE foo[] = { … } ;
#else
extern const TYPE foo[] ;
#endif

[/sourcecode]

where FOO_INITIALIZE_IT_IN_SOME_SOURCE_FILE is defined at the top of a source file that explicitly includes this header. My attempt to handle the messages was to remove the ‘extern’ from the initialization case, but I was suprised to see link errors as a result of some of those changes. It turns out that there are some subtle differences between different variations of const and extern with an array declaration of this sort. Here’s a bit of sample code:

[sourcecode language=”cpp”]
// t.h
extern const int x[] ;
extern int y[] ;
extern int z[] ;

// t.cc
#if defined WANT_LINK_ERROR
const int x[] = { 42 } ;
#else
extern const int x[] = { 42 } ;
#endif

extern int y[] = { 42 } ;
int z[] = { 42 } ;

[/sourcecode]

When WANT_LINK_ERROR isn’t defined, this produces just one clang warning message

[sourcecode language=”bash”]
t.cc:8:12: warning: ‘extern’ variable has an initializer [-Wextern-initializer]
extern int y[] = { 42 } ;
^
[/sourcecode]

Note that the ‘extern const’ has no such warning, nor does the non-const symbol that’s been declared ‘extern’ in the header. However, removing the extern from the const case (via -DWANT_LINK_ERROR) results in no symbol ‘x’ available to other consumers. The extern is required for const symbols, but generates a warning for non-const symbols.

It appears that this is also C++ specific. A const symbol in C compiled code is available for external use, regardless of whether extern is used:

[sourcecode language=”bash”]

$ clang -c t.c
t.c:5:18: warning: ‘extern’ variable has an initializer [-Wextern-initializer]
extern const int x[] = { 42 } ;
^
t.c:8:12: warning: ‘extern’ variable has an initializer [-Wextern-initializer]
extern int y[] = { 42 } ;
^
2 warnings generated.

$ nm t.o
0000000000000000 R x
0000000000000000 D y
0000000000000004 D z

$ clang -c -DWANT_LINK_ERROR t.c
t.c:8:12: warning: ‘extern’ variable has an initializer [-Wextern-initializer]
extern int y[] = { 42 } ;
^
1 warning generated.
$ nm t.o
0000000000000000 R x
0000000000000000 D y
0000000000000004 D z

[/sourcecode]

whereas that same symbol requires extern if it is const in C++:

[sourcecode language=”bash”]

$ clang++ -c t.cc
t.cc:8:12: warning: ‘extern’ variable has an initializer [-Wextern-initializer]
extern int y[] = { 42 } ;
^
1 warning generated.
$ nm t.o
0000000000000000 R x
0000000000000000 D y
0000000000000004 D z

$ clang++ -c -DWANT_LINK_ERROR t.cc
t.cc:8:12: warning: ‘extern’ variable has an initializer [-Wextern-initializer]
extern int y[] = { 42 } ;
^
1 warning generated.
$ nm t.o
0000000000000000 D y
0000000000000004 D z

[/sourcecode]

I hadn’t expected the const to interact this way with extern. I am guessing that C++ allows for the compiler to not generate symbols for global scope const variables, unless you ask for that by using extern, whereas with C you get the symbol like-it-or-not. This particular message from the clang front end is only for non-const extern initializations, making across the board fixing of messages for extern initialization of the sort above trickier. This makes it so that you can’t do an across the board replacement of extern in initializers for a given file without first ensuring that the symbol isn’t const. It looks like dealing with this will have to be done much more carefully than I first tried.