I have a situation building a C codebase with a C++ compiler that parallels this:
lib.h
extern int const values[2] = {1, 2};
lib.c
#include "lib.h"
main.c
#include <iostream>
extern int const values[2];
int main() {
std::cout << values[0] << ":" << values[1] << std::endl;
}
I had to add the extern because of something pointed out in the C++03 Standard Annex C Compatibility C.1.2 Clause 3. (Compiling with -fpermissive
will sweep this under the rug.)
Incidentally the difference it makes in how values
appears in objdump is like this before the extern
:
$ objdump -t lib.o | grep values
0000000000000000 l O .rodata 0000000000000008 _ZL6values
$ objdump -t main.o | grep values
0000000000000000 *UND* 0000000000000000 values
...and then it's like this after it is added:
$ objdump -t lib.o | grep values
0000000000000000 g O .rodata 0000000000000008 values
$ objdump -t main.o | grep values
0000000000000000 *UND* 0000000000000000 values
So the name mangling was dropped, we see an "L" turn into a "G", and the linker does not complain about values
being undefined.
Now imagine same situation with two very similar files, modified in the same way:
tmp-exttypes.h
extern const REBYTE Reb_To_RXT[REB_MAX] = { /* bunch of stuff */ };
a-lib.c
extern const REBYTE Reb_To_RXT[REB_MAX];
These are the only two Reb_To_RXT definitions in the project, built clean. But it's not linking and when I objdump the only two files that mention it I get:
$ objdump -t a-lib.o | grep Reb_To_RXT
00000000 *UND* 00000000 Reb_To_RXT
$ objdump -t f-extension.o | grep Reb_To_RXT
00000080 l O .rodata 00000038 _ZL10Reb_To_RXT
It says L, and it's name mangled. Which didn't make the much simpler example happy. But I'm wondering how this could happen with the extern on it at every appearance. Am I right to believe this is a smoking gun...and is it generally not supposed to happen that something only declared as extern should not have local linkage, anywhere?