我正在构建一个共享库,它具有相应的代码和编译规则,如下所示:
// 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
此代码编译并链接到intel(v13-v16)编译器和clang编译器(v3.6),但是使用g ++(版本4.9.2),我收到链接错误:
u.o: relocation R_X86_64_PC32 against undefined symbol `foo' can not be used when making a shared object; recompile with -fPIC
这里关于-fPIC的链接错误显然是错误的,因为代码是用fPIC编译的。我还在objdump -x
输出中看到符号的重定位记录:
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
0000000000000006 R_X86_64_PC32 foo-0x0000000000000003
clang和gcc编译器都会产生警告,指导纠正允许它链接的代码(至少这个独立版本,实际代码将更难找出修复的位置和方法):
u.C:5:10: warning: anonymous type with no linkage used to declare variable '<anonymous struct> foo' with linkage
} foo;
^
我确实可以通过删除匿名结构来解决这个问题:
// 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 ;
所以,虽然我有一个修复,但我想了解这里发生了什么。我看到一些有类似链接错误的问题:
其中一些表明这可能与符号可见性有关。 gcc是否标记此符号是否会触发最终的链接错误? g ++,clang ++或intel编译器中的哪一个在这里表现得正确或不正确,或者这个构造是无效的,只是简单的不可移植?如果这是无效代码,那么C ++标准的哪个部分违反了?
答案 0 :(得分:4)
我正在阅读3.5
部分,并且假设我正确阅读了所有内容,您的非typedef未命名类没有链接,因此不能称为extern
。
让我们快速回顾一下:
第一和第二段是定义和序言。
/3
有多种原因可以说是内部联系。它们似乎都不适用(static,const / constexpr,匿名联合)。
/4
都与未命名的命名空间相关
/5
类范围和typedef范围不适用的内容。
/6
阻止不适用的范围项目。
/7
更多块范围项。
/8
我们在这里Names not covered by these rules have no linkage....
因此,我认为链接器只是因为你试图extern
引用没有链接的东西而感到困惑。虽然错误信息似乎很糟糕/措辞不佳,但它似乎很好地发出错误。