3

我正在努力让 rLog 在 Windows 下构建为 DLL,并且我遇到了与 rlog 命名空间中的一些全局符号相关的未定义符号错误。特别是在 RLogChannel.cpp 中的这些:

namespace rlog {
...
  RLogChannel *_RLDebugChannel   = GetGlobalChannel( "debug",   Log_Debug );
  RLogChannel *_RLInfoChannel    = GetGlobalChannel( "info",    Log_Info );
  RLogChannel *_RLWarningChannel = GetGlobalChannel( "warning", Log_Warning );
  RLogChannel *_RLErrorChannel   = GetGlobalChannel( "error",   Log_Error );
...
 };

我认为问题是 1)它们没有被导出,2)它们没有在标题中声明,所以其他东西可以访问它们。所以我向它们添加了一个 __declspec(dllexport) (通过 RLOG_DECL 宏),并在标题中输入:

namespace rlog {
...
  RLOG_DECL extern RLogChannel *_RLDebugChannel;
  RLOG_DECL extern RLogChannel *_RLInfoChannel;
  RLOG_DECL extern RLogChannel *_RLWarningChannel;
  RLOG_DECL extern RLogChannel *_RLErrorChannel;
...
};

但是,无论我如何在 RLogChannel.cpp 中声明变量,我都会收到重新定义错误,尽管我在标题中将它们外部化了......这样做的正确方法是什么?似乎它应该很简单,但我不能完全理解它。

编辑:错误信息

  Error 12  error C2086: 'rlog::RLogChannel *rlog::_RLDebugChannel' : redefinition  rlog-1.4\rlog\RLogChannel.cpp   45  rlog

(所有 4 个符号相同)

编辑:我不知道发生了什么,之前的代码完全一样,但现在它会编译(感觉就像 MSVC 的怪异......),不幸的是,当链接到我的库时,符号仍然显示为未解析

4

2 回答 2

1

解决这个问题的一种方法是在一个地方和标题中定义它们一次。但是,如果您只是将所有定义转移到标题中,您最终会遇到多定义问题。

解决方案是这样的。假设文件名为 rlog.c & rlog.h

--- (rlog.h) ---
#ifdef RLOG_DEFINES
#define EXTERN
#else
#define EXTERN extern
#endif


namespace rlog {
...
  RLOG_DECL EXTERN RLogChannel *_RLDebugChannel;
  RLOG_DECL EXTERN RLogChannel *_RLInfoChannel;
  RLOG_DECL EXTERN RLogChannel *_RLWarningChannel;
  RLOG_DECL EXTERN RLogChannel *_RLErrorChannel;
...
};


--- (rlog.c) ---
#define RLOG_DEFINES
#include "rlog.h"

...

--- (other .c files) ---
#include "rlog.h"

这个解决方案的美妙之处在于,因为定义只在项目中定义一次,您永远不会让它们彼此不同步,您只需要在一个地方更改它们。想象一下,如果您将变量定义为 long 但在 extern 定义中将其声明为 short?你最终可能会产生意想不到的副作用。所以这样做有助于防止这些类型的问题。

希望有帮助。

于 2010-02-11T21:54:11.987 回答
1

我认为马特非常接近。我曾经遇到过这个问题并且是正确的(大多数便携式解决方案是这样的:

--- (rlog.h) ---
#ifdef RLOG_DEFINES
#define RLOG_DECL __declspec(dllexport)
#else
#define RLOG_DECL __declspec(dllimport)
#endif


namespace rlog {
...
  RLOG_DECL extern RLogChannel *_RLDebugChannel;
  RLOG_DECL extern RLogChannel *_RLInfoChannel;
  RLOG_DECL extern RLogChannel *_RLWarningChannel;
  RLOG_DECL extern RLogChannel *_RLErrorChannel;
...
};


--- (rlog.c) ---
#define RLOG_DEFINES
#include "rlog.h"

namespace rlog {
...
  __declspec(dllexport) RLogChannel *_RLDebugChannel   = GetGlobalChannel( "debug",   Log_Debug );
  __declspec(dllexport) RLogChannel *_RLInfoChannel    = GetGlobalChannel( "info",    Log_Info );
  __declspec(dllexport) RLogChannel *_RLWarningChannel = GetGlobalChannel( "warning", Log_Warning );
  __declspec(dllexport) RLogChannel *_RLErrorChannel   = GetGlobalChannel( "error",   Log_Error );
...
 };


--- (other .c files) ---
#include "rlog.h"

规则很简单。当您编译提供 dllexport 的 dll 时,必须在符号声明和定义中都匹配。另一方面,当外部世界使用您的库时 - 它必须显示为 dllimport 符号。

问候, Maciej Jablonski

于 2010-06-26T23:14:46.267 回答