I was using https://github.com/jdduke/three_cpp as a header-only mode but faced some issues while compiling the same with my project.
The issue happens when I include the following matrix4.hpp header (only necessary part is included) in more than one C++ files
three/core/matrix4.hpp (removed unwanted parts)
#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 (removed unwanted parts)
#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
When three/core/matrix4.hpp is included from multiple C++ files following multiple definition error is generated
/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
So based on our tryouts we noted that THREE_DECL
is not mentioned for the following functions in matrix4.hpp
Vector3 getColumnX() const;
Vector3 getColumnY() const;
Vector3 getColumnZ() const;
Matrix4& setPosition( const Vector3& v );
So after modifying these functions like follows errors are fixed
THREE_DECL Vector3 getColumnX() const;
THREE_DECL Vector3 getColumnY() const;
THREE_DECL Vector3 getColumnZ() const;
THREE_DECL Matrix4& setPosition( const Vector3& v );
Based on three/config.hpp in case of using a header-only version THREE_DECL
is defined as inline
.
What I didn't understand is
THREE_DECL
for resolving these issues?Any help will be appreciated.
This is due to the restriction based on ODR.
Why multiple definition error has occurred even if the same header is included in different compilation units?
As mentioned in the comments this is due to restrictions in the 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.
So it also answers your second query.
What will be the significance of adding
THREE_DECL
for resolving these issues?
If you check pros of using inline functions it gives you significance for the usage of inline
keyword.
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).
So if you change your functions to inline
, multiple definitions will not occur.