4
votes

I'm building a shared library that has respective code and compilation rules like the following:

// x.C
struct {
   short len;
   char s[32700];
   } foo;

// u.C
extern struct {
   short len;
   char s[32700];
   } foo;

void blah(void)
{
   foo.s[0] = 0 ;
}

$CXX -c x.C -fPIC
$CXX -c u.C -fPIC
$CXX -shared -o x.so.1 -Wl,-soname,x.so.1 x.o u.o

This code compiles and links with the intel (v13-v16) compiler and the clang compiler (v3.6), but with the g++ (version 4.9.2) I get the link error:

u.o: relocation R_X86_64_PC32 against undefined symbol `foo' can not be used when making a shared object; recompile with -fPIC

The link error here about -fPIC is clearly wrong, since the code is compiled with fPIC. I also see a relocation record for the symbol in objdump -x output:

RELOCATION RECORDS FOR [.text]:
OFFSET           TYPE              VALUE
0000000000000006 R_X86_64_PC32     foo-0x0000000000000003

Both the clang and gcc compilers produce warnings that guide correction of the code that allows it to link (at least this standalone version, the actual code will be harder to figure out where and how to fix) :

u.C:5:10: warning: anonymous type with no linkage used to declare variable '<anonymous struct> foo' with linkage
        } foo;
          ^

and sure enough I can fix this by removing the anonymous structures:

// u.h
struct fooT {
   short len;
   char s[32700];
   } ;

extern fooT foo ;

// u.C
#include "u.h"

void blah(void)
{
   foo.s[0] = 0 ;
}

// x.C
#include "u.h"

struct fooT foo ;

So, while I have a fix, I'd like to understand what's going on here. I see some questions that have similar link errors:

A couple of these indicate that this might be related to symbol visibility. Is gcc marking this symbol hidden triggering the eventual link error? Which one of the g++, clang++ or intel compilers is behaving properly or improperly here, or is this construct invalid and just plain unportable? If this is invalid code, what part of the C++ standard is it violating?

1
Maybe this'll help: stackoverflow.com/questions/332767/…. If not, you can add it to your links list :)Arnon Zilca

1 Answers

4
votes

I'm reading section 3.5 and, assuming I read everything correctly, your non-typedef unnamed class has no linkage and as such cannot be referred to as extern.

Let's just review really quick:

Paragraphs one and two are definitions and preamble.

/3 has various reasons that it would be internal linkage. None of them seem to apply (static, const/constexpr, anonymous union).

/4 is all related to unnamed namespaces

/5 class scope and typedef scope things that don't apply.

/6 Block scope items that don't apply.

/7 More block scope items.

/8 Ah here we go Names not covered by these rules have no linkage....

So it looks to me like the linker is just getting confused because you're trying to extern refer to something with no linkage. While the error message seems bad/poorly worded it does seem fine for it to emit an error.