プラグインのようなアーキテクチャを使用して、モジュールをCocoaベースのアプリケーションにロードできるようにします。すべてのモジュールは同じAPIを使用しますが、モジュールの名前と数はさまざまで、アプリケーションをビルドするときには分かりません。C++コードをラップするCocoaバンドルの動的ランタイムロード
現在、私は静的ライブラリを使用していますが、これはアプリケーション私はモジュールを追加または削除するたびに再コンパイルする私を必要とします。これを動的に行うことができます。つまり、アプリケーションを再起動して、ファイルとして追加されたモジュールのリストを更新します。
私は2つのアプローチ検討している:
- 使用動的ライブラリ(は.dylibファイル)とdlopenを使用して、実行時にそれらをロード()およびdlsymをそれら問題を複雑にココア機能
を使用して、実行時に、モジュールのコードは、このようなインターフェイスを持つC++(レガシーコード)である:
// MyModule_API.h
class MyModule_API {
public:
static MyModule* create();
static void destroy(MyModule* m);
virtual void processMap(std::map<std::string, float>) = 0;
virtual std::vector<std::string> getNames() = 0;
}
現在の静的モジュールの1つは、この(モジュールは、静的作成/破棄機能とAPIの残りの部分を実装)のように定義されます。dylibを使用して、ため、C++での名前マングリングの
#include "MyModule_API.h"
class MyModule : MyModule_API {
public:
explicit MyModule(std::string param1, std::string param2) : _param1(param1), _param2(param2) { }
~MyModule() { };
// MyModule_API:
void processMap(std::map<std::string, float>) override { ... }
std::vector<std::string> getNames() override { return std::vector<std::string({_param1, _param2}); }
private:
std::string _param1, _param2;
}
MyModule_API* MyModule_API::create() {
MyModule* m = new MyModule("foo", "bar");
//cast to base/API class before returning
return (MyModule_API*) m;
}
void MyModule_API::destroy(MyModule_API* m) {
if (m != nullptr) {
delete m;
}
}
アプリケーションはハードコーディングせずにシンボルを名前で見つけることができないため、実現不可能と考えられます。
したがって、私はObjective-Cラッパーをモジュールに使用して、それらを.appのResources/PluginsフォルダーからNSBundlesとしてインポートしようとしています。
// MyModule_ObjC.h
#import <Foundation/Foundation.h>
#include "MyModule_API.h"
@interface MyModule_ObjC : NSObject {
MyModule_API* _myModule;
}
- (id) init;
- (void) dealloc;
- (MyModule_API*) getMyModule;
@end
// MyModule_ObjC.mm
#import "MyModule_ObjC"
@implementation MyModule_ObjC
- (id)init {
self = [super init];
if (self) {
_myModule = MyModule_API::create();
}
return self;
}
- (void)dealloc {
MyModule_API::destroy(_myModule);
}
- (MyModule_API*) getMyModule {
return _myModule;
}
@end
これで、.bundleファイルを正常に構築できます。 私はその後、ココアベースのテストアプリにこのバンドルをインポートしよう:テストアプリケーションプロジェクトがないので、理にかなっている「_OBJC_CLASS _ $ _ MyModule_ObjC」...しかし、リンカは見つけることができません
#import <Cocoa/Cocoa.h>
#import <mach-o/dyld.h>
#import "MyModule_ObjC.h"
#include "MyModule_API.h"
int main(int argc, const char * argv[]) {
NSBundle *appBundle = [NSBundle mainBundle];
NSArray *bundlePaths = [appBundle pathsForResourcesOfType:@"bundle" inDirectory:@"PlugIns"];
for (id bundlePath in bundlePaths) {
NSBundle* bundle;
bundle = [NSBundle bundleWithPath:bundlePath];
[bundle load];
if (bundle) {
MyModule_ObjC* moduleAPIClass = [bundle principalClass];
if (moduleAPIClass) {
id moduleInstance;
moduleInstance = [[MyModule_ObjC alloc] init];
if (moduleInstance) {
MyModule_API* module = [moduleInstance getMyModule];
}
}
}
}
return 0;
}
MyModule_ObjC.mmのみが含まれます。 .mmを追加すると、モジュールが静的にリンクされていないため、create/destroyの静的実装が見つかりません。しかし、私はこれらの作成/破棄の実装をプラグイン/バンドルにしたい。
私のアプローチは原則ですか?
もしそうでなければ、このプラグインアーキテクチャを動作させるにはどのようなアプローチをお勧めしますか?
ありがとうございました。ありがとうございました。
は、イェンスをありがとう! Objective-Cラッパーでこの間接指示のレベルが実際にはなくなったようです:-) これは正常にリンクし、2つの独立したモジュールをロードできます。 – SideLobe
それは素晴らしいです!あなたがうまく動いてうれしいです。 –