Link Error: Duplicate Symbol
Link Error: Duplicate Symbol
我有下面列出的 4 个源文件:
//a.h
#pragma once
namespace proj {
class A {} a;
} // namespace proj
//b.h
#pragma once
namespace proj {
int foo();
} // namespace proj
// b.cpp
#include "proj/a.h"
namespace proj {
int foo() {
A b = a;
return 0;
}
} // namespace proj
// c.cpp
#include "proj/a.h"
#include "proj/b.h"
using namespace proj;
int main() {
A b = a;
foo();
return 0;
}
当我尝试编译 c.cpp
时,出现以下 link 错误:
duplicate symbol proj::a in:
buck-out/gen/proj/c#compile-c.cpp.ob5f76e97,default/c.cpp.o
buck-out/gen/proj/b#default,static/libb.a(b.cpp.o)
duplicate symbol ___odr_asan._ZN4proj1aE in:
buck-out/gen/proj/c#compile-c.cpp.ob5f76e97,default/c.cpp.o
buck-out/gen/proj/b#default,static/libb.a(b.cpp.o)
ld: 2 duplicate symbols for architecture x86_64
collect2: error: ld returned 1 exit status
Build failed: Command failed with exit code 1.
stderr: duplicate symbol proj::a in:
buck-out/gen/proj/c#compile-c.cpp.ob5f76e97,default/c.cpp.o
buck-out/gen/proj/b#default,static/libb.a(b.cpp.o)
duplicate symbol ___odr_asan._ZN4proj1aE in:
buck-out/gen/proj/c#compile-c.cpp.ob5f76e97,default/c.cpp.o
buck-out/gen/proj/b#default,static/libb.a(b.cpp.o)
ld: 2 duplicate symbols for architecture x86_64
collect2: error: ld returned 1 exit status
我假设发生这种情况是因为 b.cpp 是独立于 c.cpp 编译的,因此 pre-processor 在每个文件中分别包含 header a.h 并且当到了 link 时,linker 找到了符号 a.
的两个版本
如何声明一个 class 实例(在本例中为 a
),它可以在我的整个程序中使用并避免上述 link 错误?
参考
我在 Mac OS X 10.13.3 和 -std=c++17
.
上使用 gcc-7 (gcc-7 (Homebrew GCC 7.2.0_1) 7.2.0
)
构建系统
这应该与问题无关,但无论如何包括在内,以防有人发现它有帮助。
我正在使用 buck 使用以下 BUCK 文件编译代码(尽管这应该是不相关的):
cxx_library(
name='a',
exported_headers=['a.h'],
visibility=['PUBLIC'],
)
cxx_library(
name='b',
exported_headers=['b.h'],
srcs = ['b.cpp'],
deps = [':a'],
visibility=['PUBLIC'],
)
cxx_binary(
name='c',
srcs = ['c.cpp'],
deps = [':a', ':b'],
)
对于 c++17 标准版本之前的解决方案:1
链接器错误的原因很明显
//a.h
#pragma once
namespace proj {
class A {} a; // Declares proj::A proj::a implicitly as an instance
// everywhere a.h is included.
// Thus the linker gets confused which one to use primarly.
}
备选方案 1(一个实例):
How do I declare one instance of a class (in this case a) that is usable across my entire program and avoid the above link error?
// a.h
#pragma once
namespace proj {
class A {};
extern A a;
}
// a.cpp
#include "a.h"
namespace proj {
proj:A a;
}
备选方案 2(每个翻译单元一个实例):
// a.h
#pragma once
namespace proj {
class A {};
}
// b.cpp
#include "a.h"
namespace { // <<< unnamed (aka anonymous) namespace
// privately visible for translation unit
proj:A a;
}
// c.cpp
#include "a.h"
namespace {
proj:A a;
}
1)否则可能 最适用。
由于这是标记为 C++17,您可以利用新的 inline variables 语言功能:
namespace proj {
class A {};
inline A a;
} // namespace proj
inline
变量现在的行为方式与 inline
函数相同:a
的多个定义合并为一个。
我有下面列出的 4 个源文件:
//a.h
#pragma once
namespace proj {
class A {} a;
} // namespace proj
//b.h
#pragma once
namespace proj {
int foo();
} // namespace proj
// b.cpp
#include "proj/a.h"
namespace proj {
int foo() {
A b = a;
return 0;
}
} // namespace proj
// c.cpp
#include "proj/a.h"
#include "proj/b.h"
using namespace proj;
int main() {
A b = a;
foo();
return 0;
}
当我尝试编译 c.cpp
时,出现以下 link 错误:
duplicate symbol proj::a in:
buck-out/gen/proj/c#compile-c.cpp.ob5f76e97,default/c.cpp.o
buck-out/gen/proj/b#default,static/libb.a(b.cpp.o)
duplicate symbol ___odr_asan._ZN4proj1aE in:
buck-out/gen/proj/c#compile-c.cpp.ob5f76e97,default/c.cpp.o
buck-out/gen/proj/b#default,static/libb.a(b.cpp.o)
ld: 2 duplicate symbols for architecture x86_64
collect2: error: ld returned 1 exit status
Build failed: Command failed with exit code 1.
stderr: duplicate symbol proj::a in:
buck-out/gen/proj/c#compile-c.cpp.ob5f76e97,default/c.cpp.o
buck-out/gen/proj/b#default,static/libb.a(b.cpp.o)
duplicate symbol ___odr_asan._ZN4proj1aE in:
buck-out/gen/proj/c#compile-c.cpp.ob5f76e97,default/c.cpp.o
buck-out/gen/proj/b#default,static/libb.a(b.cpp.o)
ld: 2 duplicate symbols for architecture x86_64
collect2: error: ld returned 1 exit status
我假设发生这种情况是因为 b.cpp 是独立于 c.cpp 编译的,因此 pre-processor 在每个文件中分别包含 header a.h 并且当到了 link 时,linker 找到了符号 a.
的两个版本如何声明一个 class 实例(在本例中为 a
),它可以在我的整个程序中使用并避免上述 link 错误?
参考
我在 Mac OS X 10.13.3 和 -std=c++17
.
gcc-7 (Homebrew GCC 7.2.0_1) 7.2.0
)
构建系统
这应该与问题无关,但无论如何包括在内,以防有人发现它有帮助。
我正在使用 buck 使用以下 BUCK 文件编译代码(尽管这应该是不相关的):
cxx_library(
name='a',
exported_headers=['a.h'],
visibility=['PUBLIC'],
)
cxx_library(
name='b',
exported_headers=['b.h'],
srcs = ['b.cpp'],
deps = [':a'],
visibility=['PUBLIC'],
)
cxx_binary(
name='c',
srcs = ['c.cpp'],
deps = [':a', ':b'],
)
对于 c++17 标准版本之前的解决方案:1
链接器错误的原因很明显
//a.h
#pragma once
namespace proj {
class A {} a; // Declares proj::A proj::a implicitly as an instance
// everywhere a.h is included.
// Thus the linker gets confused which one to use primarly.
}
备选方案 1(一个实例):
How do I declare one instance of a class (in this case a) that is usable across my entire program and avoid the above link error?
// a.h
#pragma once
namespace proj {
class A {};
extern A a;
}
// a.cpp
#include "a.h"
namespace proj {
proj:A a;
}
备选方案 2(每个翻译单元一个实例):
// a.h
#pragma once
namespace proj {
class A {};
}
// b.cpp
#include "a.h"
namespace { // <<< unnamed (aka anonymous) namespace
// privately visible for translation unit
proj:A a;
}
// c.cpp
#include "a.h"
namespace {
proj:A a;
}
1)否则可能
由于这是标记为 C++17,您可以利用新的 inline variables 语言功能:
namespace proj {
class A {};
inline A a;
} // namespace proj
inline
变量现在的行为方式与 inline
函数相同:a
的多个定义合并为一个。