2009-05-17 12 views
7

スタティックライブラリの一部として、非常に基本的な「プラグインシステム」を実装しました。各「プラグイン」は、特定の画像フォーマット(例えば、 GIF、JPEGなど。また、利用可能なすべてのプラグインのリストを保持するシングルトン(PluginManagerというクラス)があります。スタティックライブラリのオブジェクト登録

難しいのは、プロジェクトファイルにソースファイルを追加または削除してプラグインを無効/有効にしたいということです。これを実現するために、各プラグインはグローバル変数(名前が異なる)を作成し、そのクラスのコンストラクターにあるプラグインをPluginManagerに登録します。これは理論的には完璧に動作しながら、他のコードに、この静的ライブラリをリンクする際

JPEG形式のため、このような何か...

struct JPEGPlugin 
{ 
    // constructor will register plugin 
    JPEGPlugin() 
    { 
    PluginManager::Singleton().RegisterPlugin(this); 
    } 

    // plenty of other code 
    ... 
}; 

JPEGPlugin jpeg_instance; // instantiate in global scope 

はしかし、それは実行可能ファイルを構築するために失敗しました。この実行可能ファイルが(jpeg_instanceのような)プラグインのグローバルにアクセスしない限り、リンカは接続を認識せず(コンストラクタの副作用を完全に無視します)、最終実行可能ファイルにコードを含めません。つまり、最終的なアプリケーションではJPEGプラグインは使用できません。

私は何年にもわたって数回問題に遭遇しましたが、私はいつも解決のためネットを検索しました。たびに、私はちょうどそれが既知の問題であり、私はそれと一緒に暮らさなければならないと基本的に言うページを見つけました。

しかし、おそらく誰かがこれを動作させる方法を知っていますか?

答えて

2

:それはこのようなものかもしれません__declspec(dllexport)に関わるクラスを宣言することによって、関連するライブラリがdllでなくても必要でした。しかし、これがなければ、リンカーは参照されていないクラスを省略します。

私たちが少し違った働きをしたレジストリソリューションで、スタックに割り当てられたオブジェクトは関与しませんでした。私はCPPユニットからパーツを持ち上げました。それは、__declspecアプローチiircを発見した場所です。

[編集]コードの一部から登録クラスの宣言も#includeにしなければなりませんでした。

+0

OK、編集に気付きました。 :) –

2

静的ライブラリであるため、プラグインを登録する代わりに、プラグインを登録することを検討してください。

 
#include "JpegPlugin.h" 

void PluginManager::RegisterPlugins() 
{ 
#idef JPEG_PLUGIN 
    RegisterPlugin(&jpeg_instance); 
#endif 
} 

JpegPlugin.hは必ずしもの定義を含める必要はありません:ヘッダーファイルマネージャは、ヘッダの包含に基づいてプラグインを登録するか否かを制御するいくつかのpreprocシンボル(すなわちJPEG_PLUGIN)を定義することができJpegPlugin。この場合、私はあなたがこの問題を解決する方法のためのソリューションを知らないが、我々はオブジェクトファクトリの静的登録と同様の問題があって、Visual Studioで、私たちが解決

 
#ifndef JPEG_PLUGIN_HEADER 
#define JPEG_PLUGIN_HEADER 

#if 0 // change this to 1 to use the plugin 
#define JPEG_PLUGIN 
#include "Jpeg_PluginCls.h" 
#endif 

#endif 
+1

答えをありがとう。しかし、あなた自身が指摘しているように、これはマネージャーからプラグインへの依存関係を導入しています。私が避けたいものです!その理由は、他の人がマネージャークラスを変更することなくプラグインを実装する必要があるからです。 – beef2k

+1

ここでの解決方法は、静的なlibのユーザが、あなたの例でメカニズムを介して独自のプラグインを登録することを排除するものではありません(マネージャは元の例で同じRegisterPluginメソッドを呼び出します。静的ライブラリに同梱されているプラ​​グインを、プラグイン自体を明示的に参照することなく、ユーザがリンクしているマネージャが利用できるようにします。 –

1

これはHarald Scheirich's answerのフォローアップです。

私はMSVC++ 2005のリリースモード(ただしデバッグモードではない)が、LINK documentationによれば、参照されていないシンボルを削除するリンカに対して/OPT:REFフラグをオンにするようです最後のEXE。そして、the webpage for __declspec(selectany)は、グローバルオブジェクトのコンストラクタがオブジェクトへの参照であるとみなされていないことを示しているようです(IMHOは間違っていますが、そこにはあります)。だから私の推測では、この問題はデバッグビルドのために "なくなる"ということです - それは正しいのですか?

したがって、私は、__declspec(dllexport)を使用するという提案は、ソースコード内で指定されているため、シンボルを「参照済み」としてマークするのに便利な方法だと思います。なんらかの理由でシンボルのエクスポートを避けたい場合は、/INCLUDE:mysymbol linker flagを使用するか、/OPT:REFフラグをオフにして同じことを達成できると思われます。

+0

私たちはデバッグビルドで同じ問題を抱えていましたが、システム全体がやや脆いです。この作業のもう一つの条件は、.hファイルがどこかの場所からインクルードされなければならないということでした。だから、問題はデバッグビルドで取り除かれません。 唯一のもう一つの問題は、別の場所から静的に到達したコード内の直接参照がある場合です。 –

+0

興味深い。グローバル変数のコンストラクタにクラスを登録することは、プラグインシステムを開発するための素晴らしい、維持可能な方法なので、この権利を得ることは非常に難しいことは残念です。 –

+0

私たちは、デバッグとリリースビルドの問題に直面しています。 Visual Studioだけでなく、GCCでも同様です。 – beef2k

0

てください:

  1. は、exeファイルのプロジェクトへの参照
  2. 「リンクライブラリの依存関係」の両方を設定し、真のよう「入力としてリンクライブラリの依存関係を使用してください」のような静的libにプロジェクトを追加します。

はこれを参照してください。 「入力として使用リンクライブラリの依存関係が」Yesに設定されているconfig

、依存プロジェクトによって生成.LIBS用の.objファイル内のプロジェクト・システム・リンク。だから、すべてのシンボルは保持されます。