Multiple definition error (collect2: error: ld returned 1 exit status)

Multiple definition error (collect2: error: ld returned 1 exit status)

我使用 https://github.com/jdduke/three_cpp 作为 header-only 模式,但在用我的项目编译时遇到了一些问题。

当我在多个 C++ 文件中包含以下 matrix4.hpp header(只包含必要的部分)时会出现此问题

three/core/matrix4.hpp(删除不需要的部分)

#ifndef THREE_MATRIX4_HPP
#define THREE_MATRIX4_HPP

#include <three/common.hpp>

#include <three/core/math.hpp>
#include <three/core/quaternion.hpp>
#include <three/core/vector3.hpp>
#include <three/core/vector4.hpp>

namespace three {

class Matrix4 {
public:
  // Function without any erros
  THREE_DECL Matrix4();
  THREE_DECL Vector3    getScale() const;

  // Error causing functions
  Vector3 getColumnX() const;
  Vector3 getColumnY() const;
  Vector3 getColumnZ() const;
  Matrix4& setPosition( const Vector3& v );
};

} // namespace three

#if defined(THREE_HEADER_ONLY)
# include <three/core/impl/matrix4.ipp> // This is where all this functions is defined.
#endif // defined(THREE_HEADER_ONLY)

#endif // THREE_MATRIX4_HPP

three/core/impl/matrix4.ipp(删除不需要的部分)

#ifndef THREE_MATRIX4_IPP
#define THREE_MATRIX4_IPP

#include <three/core/matrix4.hpp>

namespace three {

Matrix4::Matrix4() {
  identity();
}

Matrix4::Matrix4( const Matrix4& other ) {
  copy( other );
}

Vector3 Matrix4::getScale() const {
  auto sx = Vector3( te[0], te[1], te[2] ).length();
  auto sy = Vector3( te[4], te[5], te[6] ).length();
  auto sz = Vector3( te[8], te[9], te[10] ).length();
  return Vector3( sx, sy, sz );
}

Vector3 Matrix4::getColumnX() const {
  return Vector3( te[0], te[1], te[2] );
}

Vector3 Matrix4::getColumnY() const {
  return Vector3( te[4], te[5], te[6] );
}

Vector3 Matrix4::getColumnZ() const {
  return Vector3( te[8], te[9], te[10] );
}

Vector3 Matrix4::getPosition() const {
  return Vector3( te[12], te[13], te[14] );
}

} // namespace three

#endif // THREE_MATRIX4_IPP

当 three/core/matrix4.hpp 从多个 C++ 文件中包含时,会产生多个定义错误

/usr/bin/ld: /tmp/ccmYWwMM.o: in function `std::_Rb_tree_const_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, bool> >::_Rb_tree_const_iterator(std::_Rb_tree_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, bool> > const&)':
/home/three/core/impl/matrix4.ipp:617: multiple definition of `three::Matrix4::setPosition(three::Vector3 const&)'; /tmp/ccSaHLVI.o:/home/three/three/core/impl/matrix4.ipp:617: first defined here
/usr/bin/ld: /tmp/ccmYWwMM.o: in function `three::Vector3::subSelf(three::Vector3 const&)':
/home/three/three/core/impl/matrix4.ipp:627: multiple definition of `three::Matrix4::getColumnX() const'; /tmp/ccSaHLVI.o:/home/three/three/core/impl/matrix4.ipp:627: first defined here
/usr/bin/ld: /tmp/ccmYWwMM.o: in function `three::Matrix4::getColumnY() const':
/home/three/three/core/impl/matrix4.ipp:631: multiple definition of `three::Matrix4::getColumnY() const'; /tmp/ccSaHLVI.o:/home/three/three/core/impl/matrix4.ipp:631: first defined here
/usr/bin/ld: /tmp/ccmYWwMM.o: in function `three::Matrix4::getColumnZ() const':
/home/three/three/core/impl/matrix4.ipp:635: multiple definition of `three::Matrix4::getColumnZ() const'; /tmp/ccSaHLVI.o:/home/three/three/core/impl/matrix4.ipp:635: first defined here
collect2: error: ld returned 1 exit status

因此,根据我们的试用,我们注意到 matrix4.hpp

中的以下功能未提及 THREE_DECL

所以在修改这些函数后,如下错误得到修复

基于 three/config.hpp 在使用 header-only 版本的情况下 THREE_DECL 定义为 inline

没看懂的是

  1. 为什么相同的header包含在不同的编译单元中也会出现多重定义错误?
  2. 添加THREE_DECL对解决这些问题有何意义?

任何帮助将不胜感激。

这是基于 ODR 的限制。

Why multiple definition error has occurred even if the same header is included in different compilation units?

如评论中所述,这是由于 One Definition Rule(ODR).

中的限制所致

The One Definition Rule (ODR) is an important rule of the C++ programming language that prescribes that objects and non-inline functions cannot have more than one definition in the entire program and template and types cannot have more than one definition by translation unit. It is defined in the ISO C++ Standard (ISO/IEC 14882) 2003, at section 3.2.

所以它也回答了你的第二个问题。

What will be the significance of adding THREE_DECL for resolving these issues?

如果您勾选 pros of using inline functions,则表明 inline 关键字的使用意义重大。

By marking it as inline, you can put a function definition in a header file (i.e. it can be included in multiple compilation unit, without the linker complaining).

因此,如果您将函数更改为inline,则不会出现多重定义。