プラグインスタイルのシステムを実装するためのヒントは何ですか?
Cでは(私自身は行っていませんが、C++もそうだと思います)、これは通常、動的にロードされたモジュールを使用して行われます。そのようなAPIはプラットフォームに依存します。
POSIX(Linux)では、dlopen()
ファミリーの関数を使用します。基本的に、プラグインを個別にビルドし、実行時にロードし、名前でシンボルを検索して、それらを呼び出すことができます。
Win32の場合、非常によく似た処理を行うLoadLibrary()
があり、コードをDLLにビルドします。
これらすべてを簡単かつ透過的にする便利なラッパーについては、GLibの GModule APIを確認してください。
'92/'93の時間枠で、C++でコーディングされたAldusPageMakerのプラグインアーキテクチャに取り組みました。 PageMakerは、VAMPと呼ばれるC++ OOPフレームワーク上に構築されており、MacOSとWindows間の移植性を支援しました。
そこで、C++の機能を使用してプラグインアーキテクチャを構築しようとしました。これは、いわゆる脆弱な基本クラスの問題のため、C++クラスにとって非常に問題があることが判明しました。ジャーナルに掲載され、OOPSLA'93でリフレクションワークショップで発表した論文を書き始めました。また、ポートランドで開催されたUsenixカンファレンスでBjarne Stroustrupと連絡を取り、数か月間彼と対話を続けました。そこで彼は、私に代わって脆弱な基本クラスの問題に対処する問題を支持しました。 (残念ながら、当時は他の問題がより重要であると考えられていました。)
Microsoftは、COM/DCOMシステムを導入し、そのプラットフォームに対して、問題の実行可能な解決策と見なされていました。 C++は、COMインターフェイスの定義に使用される抽象クラスを介してCOMの実装言語として使用できます。
ただし、最近の開発者はCOM/DCOMを避けています。
対照的に、NeXTは、NeXTステップフレームワークで90年代初頭にObjectiveCを使用してプラグインアーキテクチャを考案しました。今日、それはAppleのコンピューターやiPhoneなどの重要なプラットフォーム上のMac OSXで活気に満ちています。
プラグインの問題を優れた方法で解決できるObjectiveCを提出します。
私は個人的に、C++の脆弱な基本クラスの問題が最も致命的な欠陥であると考えています。
Cベースの言語ファミリーでプラグインアーキテクチャを構築する場合は、ObjectiveCを使用して構築します。
私が与えることができる最高のプラットフォームと言語中立のアドバイスはこれです:
プラグインSDKを中心にアプリ全体を設計します。
IMO、プラグインSDKは後から考えるべきではありません。基本的にプラグインをロードする空のシェルになるようにアプリを設計すると、コア機能が独自のSDKに実装され、次の利点が得られます。
C/C++では、おそらく動的リンクライブラリと、関数ポインタ(C)またはインターフェイス(C++の場合は純粋仮想メソッドのみで構成されるクラス)のいずれかを使用します。ただし、Javascriptを使用している場合でも、上記のアーキテクチャをお勧めします。
QtはQPluginLoaderを提供します: http://qt-project.org/doc/qt-4.8/qpluginloader.html
よりきめ細かい制御が必要/必要な場合、QtはQLibraryを使用してライブラリをオンザフライでロードする手段も提供します: http://qt-project.org/doc/qt-4.8/qlibrary.html
さらに良いことに、これらはプラットフォーム間で移植可能です。
これはあなたが探しているものではないかもしれませんが、Luaなどのスクリプト言語をアプリケーションに埋め込むことができます。 Luaは他のプログラムに埋め込まれるように設計されており、プラグインを作成するためのスクリプト言語として使用されます。 Luaインタープリターをプログラムに追加するのはかなり簡単だと思いますが、Luaを知らないので、これがどれほど効果的なソリューションであるかを保証することはできません。 Luaの使用経験が豊富な他の人は、Luaを別のアプリケーションに埋め込んだ経験についてコメントを追加してください。
もちろん、これはプラグインをLuaで作成する必要があることを意味します。 Luaが気に入らない場合は、de-facto標準のPerl、PythonおよびRubyインタープリターはすべてCで記述されています、 Cプログラムに埋め込むことができます。これらの言語をスクリプト言語拡張として使用するプログラムをいくつか知っています。
しかし、あなたの質問は少し曖昧なので、私はあなたが何を探しているのかわかりません。おそらく、上記のプラグインを使って人々に何をしてもらいたいかについてのより多くの情報が適切でしょう。一部のタスクでは、本格的なスクリプト言語は少しやり過ぎかもしれません。
プラットフォーム固有のコーディングから(可能な限り)保護するACE( http://www.cs.wustl.edu/~schmidt/ACE.html )のようなフレームワークを使用するのが最善です。
ACEには、動的にアセンブルされたアプリケーションを作成するために使用できる共有ライブラリに基づくプラグインフレームワークが含まれています。
より高いレベルの抽象化については、CIAO( http://www.cs.wustl.edu/~schmidt/CIAO.html )CORBAコンポーネントモデルのオープンソースC++実装を確認してください。
Poco Class Loader を見てください、それはあなたにとって興味深いかもしれません。
ダイナミックリンクライブラリを使用してプラグインシステムを実装する方法についての記事を書きました。この記事はWindowsプログラマーの観点から書かれていますが、この手法はLinux/Unixタイプの環境にも適用できます。
記事はここで見つけることができます: http://3dgep.com/?p=1759
重要な点は、メインアプリケーション(コアアプリケーション)とプラグイン実装の両方によって暗黙的にリンクされる「共通」DLLを作成する必要があるということです。その後、プラグインを明示的にリンクして、コアアプリケーションによって実行時に動的にロードされます。
この記事では、「共通」DLLを使用して、クラスの静的(シングルトン)インスタンスを複数のDLL間で安全に共有する方法も示しています。
この記事では、「C」関数または変数をDLLからエクスポートし、実行時にアプリケーションでエクスポートされた関数を使用する方法も示しています。
プラグインアーキテクチャに関するこのポッドキャスト も興味深いかもしれません。
プラグインライブラリを作成しました Pugg dllファイルからC++クラスをロードします。使用したロジックは次のとおりです。
ユーザーは、一意の名前を持つdllからc関数をエクスポートします。この名前は、dllからのロード中に引数を使用して関数を区別できないため、十分に一意である必要があります。
C関数は、「ドライバ」と呼ばれる1つまたは複数のファクトリクラスを登録します。すべてのDriverクラスは文字列に関連付けられています。メインアプリケーションがクラスを作成する場合、関連する文字列を使用して関連するファクトリクラスを収集します。また、古いプラグインをロードしないようにバージョンチェックシステムを実装しました。
DLLのロードは、LoadLibraryA関数とGetProcAddress関数を使用して実行されます(Puggは現在Windowsで機能します)。
言及する価値のあることの1つは、メインアプリケーションとdllは、同じコンパイラを使用し、同じコンパイルオプション(リリース/デバッグモード、最適化設定、stlバージョンなど)を使用してコンパイルする必要があるということです。そうしないと、クラスのマッピングに問題が発生する可能性があります。
私はかなり素朴なシステムを使用していくつかの成功を収めました: