结合使用内联数学库和预编译头文件时出现链接错误
我今天遇到了一个相当奇怪的问题。我有一个针对 SSE 优化的数学库,因此几乎所有功能都被声明为内联。为了简化起见,我将仅使用一个类 Vector3 来解释问题:
Vector3 在 Vector3.h 中声明,如下所示:
#ifndef VIRTUS_VECTOR3_H
#define VIRTUS_VECTOR3_H
#ifndef VEC3INLINE
#if(_DEBUG)
#define VEC3INLINE inline
#else
#define VEC3INLINE __forceinline
#endif
#endif
namespace Virtus {
struct Vector3
{
union
{
struct { f32 x,y,z; };
f32 v[3];
};
Vector3(void);
Vector3(const Vector3& rhs);
Vector3(f32 xx, f32 yy, f32 zz);
VEC3INLINE Vector3& operator=(const Vector3& rhs);
VEC3INLINE Vector3 operator+(f32 rhs) const;
VEC3INLINE Vector3 operator-(f32 rhs) const;
VEC3INLINE Vector3 operator*(f32 rhs) const;
VEC3INLINE Vector3 operator/(f32 rhs) const;
VEC3INLINE Vector3& operator+=(f32 rhs);
VEC3INLINE Vector3& operator-=(f32 rhs);
...
#include "vector3.inl"
#endif
在 vector3.inl 中,我继续定义所有函数
namespace Virtus {
Vector3::Vector3(void)
: x(0.0f), y(0.0f), z(0.0f)
{
}
Vector3::Vector3(const Vector3& rhs)
: x(rhs.x), y(rhs.y), z(rhs.z)
{
}
Vector3::Vector3(f32 xx, f32 yy, f32 zz)
: x(xx), y(yy), z(zz)
{
}
VEC3INLINE Vector3& Vector3::operator=(const Vector3& rhs)
{
memcpy(v, rhs.v, sizeof(v));
return *this;
}
...
,然后将所有数学对象包含在一个文件中名为 math.h
#ifndef VIRTUS_MATH_H
#define VIRTUS_MATH_H
#include "vector2.h"
#include "vector3.h"
#include "vector4.h"
#include "matrix4.h"
#include "primesearch.h"
namespace Virtus
{
class MathException
{
public:
enum ErrorCode
{
PRIME_SEARCH_INVALID_ELEMENTS,
PRIME_SEARCH_UNSUFFNUM_PRIMES
};
MathException(ErrorCode code) : m_Error(code) {}
ErrorCode What(void) const { return m_Error; }
private:
ErrorCode m_Error;
};
} // namespace virtus
#endif // Include Guard
的文件包含在我的预编译头文件(precompiled.h 又名 stdafx.h)中。
我使用 Visual Studio 2008,它会自动从构建过程中排除 .inl 文件。
这是我收到的链接器错误:
错误 1 错误 LNK2005:“公共: __thiscall Virtus::Vector3::Vector3(void)" (??0Vector3@Virtus@@QAE@XZ) 已经 定义于 precompiled.obj main.obj Virtus
我尝试了几乎所有可以想象到的方法来修复这个问题,比如手动从构建中排除所有 inl 文件;不将 math.h 包含在预编译文件中,但只包含在我需要的地方(在这种情况下,我会得到类似的已定义链接器错误);从 inl 扩展名更改为 cpp 扩展名等。我能够修复它的唯一方法是使用 #pragma 一次而不是包含防护。所以我现在最好的猜测是它与预编译头文件和包含防护的组合有关,但我不太确定如何解决这个问题。
非常感谢您的帮助!
I came about a rather weird problem today. I have a math library optimized for SSE, therefore almost all functionality is declared as inline. For simplification purposes I will only explain the problem using one class, Vector3:
Vector3 is declared in Vector3.h, something like this:
#ifndef VIRTUS_VECTOR3_H
#define VIRTUS_VECTOR3_H
#ifndef VEC3INLINE
#if(_DEBUG)
#define VEC3INLINE inline
#else
#define VEC3INLINE __forceinline
#endif
#endif
namespace Virtus {
struct Vector3
{
union
{
struct { f32 x,y,z; };
f32 v[3];
};
Vector3(void);
Vector3(const Vector3& rhs);
Vector3(f32 xx, f32 yy, f32 zz);
VEC3INLINE Vector3& operator=(const Vector3& rhs);
VEC3INLINE Vector3 operator+(f32 rhs) const;
VEC3INLINE Vector3 operator-(f32 rhs) const;
VEC3INLINE Vector3 operator*(f32 rhs) const;
VEC3INLINE Vector3 operator/(f32 rhs) const;
VEC3INLINE Vector3& operator+=(f32 rhs);
VEC3INLINE Vector3& operator-=(f32 rhs);
...
#include "vector3.inl"
#endif
In vector3.inl I proceed with defining all of the functions
namespace Virtus {
Vector3::Vector3(void)
: x(0.0f), y(0.0f), z(0.0f)
{
}
Vector3::Vector3(const Vector3& rhs)
: x(rhs.x), y(rhs.y), z(rhs.z)
{
}
Vector3::Vector3(f32 xx, f32 yy, f32 zz)
: x(xx), y(yy), z(zz)
{
}
VEC3INLINE Vector3& Vector3::operator=(const Vector3& rhs)
{
memcpy(v, rhs.v, sizeof(v));
return *this;
}
...
I then include all of my math objects in a file called math.h
#ifndef VIRTUS_MATH_H
#define VIRTUS_MATH_H
#include "vector2.h"
#include "vector3.h"
#include "vector4.h"
#include "matrix4.h"
#include "primesearch.h"
namespace Virtus
{
class MathException
{
public:
enum ErrorCode
{
PRIME_SEARCH_INVALID_ELEMENTS,
PRIME_SEARCH_UNSUFFNUM_PRIMES
};
MathException(ErrorCode code) : m_Error(code) {}
ErrorCode What(void) const { return m_Error; }
private:
ErrorCode m_Error;
};
} // namespace virtus
#endif // Include Guard
and math.h is included in my precompiled header file (precompiled.h aka stdafx.h)
I use Visual Studio 2008, which should automatically exclude .inl files from the build process.
This is the linker error I am getting:
Error 1 error LNK2005: "public:
__thiscall Virtus::Vector3::Vector3(void)"
(??0Vector3@Virtus@@QAE@XZ) already
defined in
precompiled.obj main.obj Virtus
I tried fixing this pretty much every way imaginable, like excluding all inl files from the build manually; not including math.h in the precompiled file but only where I need it ( in which case I get a similar already defined linker error); changing from the inl extension to cpp extension, and so on. The only way I was able to fix it was using #pragma once instead of include guards. So my best guess at this time is that it has something to do with the combination of precompiled header files and include guards, but I'm not really sure how to fix this.
Help would be much appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
vector3.inl 中的每个定义都需要使用
inline
显式定义。Each of the definitions inside vector3.inl needs to be explicitly defined with
inline
.