链接错误:重复符号

时间:2018-02-08 19:26:16

标签: c++ linker header-files c++17 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时,我收到以下链接错误:

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编译的,所以预处理器在每个文件中单独包含头啊,当需要链接时,链接器会找到两个版本的符号a

如何声明可在整个程序中使用的一个类实例(在本例中为a)并避免上述链接错误?

参考

我在Mac OS X 10.13.3上使用gcc-7(gcc-7 (Homebrew GCC 7.2.0_1) 7.2.0-std=c++17

构建系统

这应该与问题无关,但无论如何,如果有人认为它有帮助,

我使用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'],
)

2 个答案:

答案 0 :(得分:3)

由于这是标记为C ++ 17,因此您可以利用新的inline variables语言功能:

func TestSomeFunction(t *testing.T) {
 .
 .
 .

    w := httptest.ResponseRecorder{}
    err := SomeFunction(w, ...)
 .
 .
}

namespace proj { class A {}; inline A a; } // namespace proj 变量现在的行为与inline函数的行为相同:inline的多个定义会折叠为一个。

答案 1 :(得分:0)

对于 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(单个实例):

  

如何声明可在整个程序中使用的类的一个实例(在本例中为a)并避免上述链接错误?

// 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) 否则@Barry's answer可能最适用。