1

ロードされた実行可能ファイルに含まれる静的変数にアクセスする必要がある共有ライブラリ (Linux では .so、Windows では .dll) があります。この変数はたまたまクラス テンプレート タイプであり、名前空間内にあります。変数を「extern」(および Windows では「__declspec(dllimport)」) として宣言しているにもかかわらず、DLL がリンクされている場合、VC10 はこの変数に対して「未解決の外部シンボル」エラーを出します。これは実際には解決されるべきではなく、代わりにロード時間に残されるべきであるため、私には奇妙に思えます。

ヘッダー:

// a header demonstrating MSVC-compatible linkage
#ifdef _MSC_VER

#ifdef I_AM_DLL
#define TO_DLL_LINKAGE __declspec( dllimport )
#else
#define TO_DLL_LINKAGE __declspec( dllexport )
#endif

#else  // not MSVC
#define TO_DLL_LINKAGE
#endif

template<class T>
class TheClass
{
public:
   TheClass(T t) : value_(t) {}

   T value() const
   {
      return value_;
   }
private:
   T value_;
};

typedef TheClass<int> MyClass;

そしてDLL:

// a test library (DLL) for linkage experiment
#define I_AM_DLL
#include "theclass.hpp"

#include <iostream>

namespace foo {
extern TO_DLL_LINKAGE MyClass theObject;
}

void bar() {
   int i = foo::theObject.value();
   std::cout << "object value is " << i << std::endl;
}

エラー:

エラー LNK2001: 未解決の外部シンボル "_ declspec(dllimport) クラス TheClass foo::theObject" ( _imp_?theObject@foo@@3V?$TheClass@H@@A)

これが gcc で問題なく動作することは言うまでもありません。同様の StackOverflow の質問もいくつか確認しましたが、既に行っていることを推奨しているか、さまざまな理由 (インポートではなくエクスポート、クラス インスタンスではなくクラスなど) で適用されていません。

MSVC10 を満足させるには、どのような追加の魔法が必要ですか? ありがとう。

4

1 に答える 1

1

ここには2つの基本的な問題があることがわかります。

  1. Windowsでは、共有ライブラリの場合でも、シンボル解決はリンク時に実行されます
  2. dllimportとdllexportは非対称です-すべてのdllimportsを解決する必要があります

Linuxでgccを使用して実行している場合、オブジェクトへの「外部」参照はプログラムのロード時に解決されるため、私のプログラムは機能します。共有ライブラリ(.so)は、エクスポートしているシンボルとインポートしているシンボルを一覧表示し、OSのプログラムローダーは、プログラムの起動時にメインプログラムと共有ライブラリの両方のすべてのインポートが満たされていることを確認します。

対照的に、Windows / VC ++の世界では、インポートされたシンボルを満たす特定のモジュールは、共有ライブラリがリンクされているため、通常は「インポートライブラリ」または.libファイルを介して識別される必要があります。これは、プログラムのロード時間に延期することはできません。したがって、リンクステップは失敗します。

私の特定の状況では、共有ライブラリからのシンボルを必要とし、共有ライブラリに(1つの)シンボルを提供する実行可能モジュールがあります。静的ライブラリおよびgcc/Linuxの場合は問題ありませんが、Windows /VC++の場合は循環依存関係が作成されます。解決策はありますが、このStackOverflowの質問、Microsoftのドキュメントで説明されているように、追加の作業が必要です。つまり、これを行うには、共有ライブラリのリンク段階で使用するために実行可能ファイルからインポートライブラリが生成される、より複雑なリンク手順が必要になります。__dllspec(dllexport)がある場合、このようなライブラリは自動的に生成されます。任意のデータのストレージクラス。最後のステップは、このインポートライブラリを共有ライブラリDLLのリンクステージに追加することです。

私のように、CMakeユーザーの場合、このプロセスは、ライブラリが実行可能ファイルに「リンク」できるようにするENABLE_EXPORTSと呼ばれる特別なターゲットプロパティによってはるかに簡単になります。

于 2012-11-28T20:38:41.840 に答える