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)他のものがアクセスできるように、ヘッダーで宣言されていないことだと思いました。そこで、(RLOG_DECLマクロを介して)__ declspec(dllexport)を追加し、ヘッダーに次のように配置しました。

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.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 シンボルとして表示される必要があります。

よろしく、マチェイ・ヤブロンスキー

于 2010-06-26T23:14:46.267 に答える
1

この問題を回避する 1 つの方法は、それらを 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"

このソリューションの優れた点は、定義がプロジェクトで 1 回だけ定義されるため、互いに同期が取れなくなることがなく、1 か所で変更するだけで済むことです。変数を long として定義したが、extern 定義では short として宣言されていると想像してみてください。予期しない副作用が発生する可能性があります。したがって、このようにすることで、この種の問題を防ぐことができます。

それが役立つことを願っています。

于 2010-02-11T21:54:11.987 に答える