Plugin APIについて
Westonでモジュール開発をおこなっていると、他のモジュールが持つ機能を呼び出したいときがしばしばある。
しかしWestonにおいてはモジュールが直接他のモジュールをリンクすることは非推奨となっており、また関数自体も直接公開とはなっていない(WL_EXPORT
が付いていない)ことが多い。
替わりにWestonにはPlugin APIという仕組みが存在している。モジュールはPlugin APIを通じて自身の関数を他のモジュールに公開することができるようになっている。
また、同一のAPIに対してモジュール毎に別の実装を与えるということもできるため、擬似的なポリモーフィズムも実現しているといえる。
Plugin APIの利用
実際にPlugin APIを実装してみよう。
面白みに欠ける例であるが、ログに挨拶を出力するvoid greet(const char* name)
関数をPlugin APIを通じて外部に公開してみよう。
API提供側
まずはヘッダファイルgreeting-plugin.hを作成する。
#pragma once
#include <libweston/libweston.h>
#include <libweston/plugin-registry.h>
#define WESTON_GREETING_API_NAME "weston_greeting_api_v1"
#ifdef __cplusplus
extern "C" {
#endif
struct weston_greeting_api {
void (*greet)(const char *name);
};
static inline const struct weston_greeting_api *
weston_greeting_get_api(struct weston_compositor *compositor)
{
const void *api;
api = weston_plugin_api_get(compositor, WESTON_GREETING_API_NAME,
sizeof(struct weston_greeting_api));
return (const struct weston_greeting_api *)api;
}
#ifdef __cplusplus
}
#endif
将来的にAPIがバージョンアップする可能性を考えてAPIを識別する文字列(WESTON_GREETING_API_NAME
)にはバージョン番号を含めておくのが推奨される。
次にモジュール(もしくはシェル)コード内で関数を実装し、weston_greeting_api
のインスタンスに登録する。(greeting-plugin.hのインクルードを忘れずに)
extern "C" void greet(const char* name)
{
weston_log("my-shell: Hello %s\n", name);
}
static const struct weston_greeting_api greeting_api = {
.greet = greet,
};
そして、APIを登録する。登録する場所はwet_shell_init()
もしくはwet_module_init()
内が良いだろう。
weston_plugin_api_register(compositor,
WESTON_GREETING_API_NAME,
&greeting_api, sizeof(greeting_api));
これでgreet()
関数がPlugin APIとして外部に公開された。
課題1.
API識別文字列にバージョン番号を含めるとバージョンアップ時にどのようなメリットがあるか。
またどのような場合にバージョン番号を変えるべきか。
課題2.
greeting-plugin.hヘッダ内のextern "C"
は必須だろうか、必須ではないだろうか、理由を含めて考えてみよう。
API利用側
APIを利用する場合は必要なヘッダ(ここではgreeting-plugin.h)をインクルードしヘッダ内のAPI取得関数を呼び出すだけで使用可能となる。
const weston_greeting_api* greeting_api = weston_greeting_get_api(compositor);
greeting_api->greet("Taro");
注意
モジュールでAPIが登録されている場合はモジュールのロード順によってAPI登録よりも先にAPI呼び出しがおこなわれて失敗する可能性があることに注意しよう。
API登録をおこなうモジュールが先にロードされるように順序を調整する必要がある。