0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Weston/Wayland入門③ Westonを拡張する

Last updated at Posted at 2025-07-03

Weston/Wayland入門まとめ

今回はWeston用に拡張モジュールを作成し独自のインターフェイスを実装してみる。

開発環境

開発環境は以下を想定する。

  • OS: Debian trixie(testing)
  • 言語: C++20
  • Weston14

異なる環境を使用する場合は適宜記述を読み替えること。

ハンズオン

今回はmy-custom-moduleという名前のモジュールを作成する。Linuxの場合はビルドするとmy-custom-module.soが生成され、--modules=を指定することでモジュールを組み込んだwestonが起動する。

$ weston --modules=my-custom-module.so

必要パッケージ

Debian系であれば、weston, libweston-14-devをインストールしておく。

$ sudo apt install weston libweston-14-dev

空のモジュールを作成

まずはメッセージを表示するだけの空モジュールを作成する。

module.cpp
#include <wayland-server-core.h>
#include <weston.h>

extern "C" {

WL_EXPORT int wet_module_init(weston_compositor *compositor,
                              int *argc, char* argv[])
{
    weston_log("Hello my custom module\n");

    return 0;
}

}
  • モジュールは必ず最初にwet_module_init()関数が呼ばれる。C関数として呼ばれるためextern "C"が必須
    WL_EXPORTwet_module_init()を外部公開するために必要

CMakeLists.txtは以下の通り。

CMakeLists.txt
cmake_minimum_required (VERSION 3.10)
project(my-custom-module)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(PkgConfig REQUIRED)
pkg_check_modules(WAYLAND_CLIENT wayland-server REQUIRED)
pkg_check_modules(WESTON libweston-14 REQUIRED)

add_library(${CMAKE_PROJECT_NAME} MODULE
    module.cpp
)

set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")

target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE
    ${WAYLAND_SERVER_INCLUDE_DIRS}
    ${WESTON_INCLUDE_DIRS}
)

target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
    ${WAYLAND_SERVER_LIBRARIES}
    ${WESTON_LIBRARIES}
)

cmakeでライブラリをビルドするとlibmy-custom-module.soのような名前となるが、westonモジュールは慣習的にlibプレフィックスを付けないため、以下のオプションで抑制している。

set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")

これによりビルドした結果my-custom.module.soという名前でビルドされる。

ビルド

$ cmake -S . -B build
$ cmake --build build

build/my-custom-module.soがビルドされる。

実行

$ weston --modules=$(pwd)/build/my-custom-module.so

ログに出力があることを確認する。

[14:08:46.123] Hello my custom module

greetingプロトコル定義

以下のXMLで今回使用するプロトコルを定義した。greetingインターフェイスに対して

greeting.xml
<protocol name="greeting_protocol">

  <interface name="greeting" version="1">
    <request name="greet">
      <arg name="name" type="string"/>
    </request>
    <event name="done">
    </event>
  </interface>

</protocol>
  • greeting()リクエストでnameを送信するとログに挨拶を出力
  • done()イベントで処理の完了を通知

という仕様にする。

クライアントのときど同様にXMLからコードを生成しビルドをおこなう。

CMakeLists.txt(抜粋)
find_program(WAYLAND_SCANNER wayland-scanner REQUIRED)

set(GREETING_XML ${CMAKE_CURRENT_SOURCE_DIR}/greeting.xml)
set(GREETING_HEADER ${CMAKE_CURRENT_BINARY_DIR}/greeting-server-protocol.h)
set(GREETING_SOURCE ${CMAKE_CURRENT_BINARY_DIR}/greeting-server-protocol.c)

add_custom_command(
        OUTPUT  ${GREETING_HEADER}
        COMMAND ${WAYLAND_SCANNER} server-header ${GREETING_XML} ${GREETING_HEADER}
        DEPENDS ${GREETING_XML}
        VERBATIM
)

add_custom_command(
        OUTPUT  ${GREETING_SOURCE}
        COMMAND ${WAYLAND_SCANNER} private-code ${GREETING_XML} ${GREETING_SOURCE}
        DEPENDS ${GREETING_XML}
        VERBATIM
)

add_custom_target(protocol ALL DEPENDS ${GREETING_SOURCE} ${GREETING_HEADER})

既存部分の修正も忘れずに。

CMakeLists.txt(抜粋)
add_library(${CMAKE_PROJECT_NAME} MODULE
    module.cpp
    ${GREETING_SOURCE}
)

add_dependencies(${CMAKE_PROJECT_NAME} protocol)

greetingグローバルオブジェクト作成

wet_module_init()内にてwl_global_create()関数でgreetingインターフェイスに対応するグローバルオブジェクトを作成する。

module.cpp(抜粋)
extern "C" {

WL_EXPORT int wet_module_init(weston_compositor *compositor,
                              int *argc, char* argv[])
{
    weston_log("my-custom-module: Hello my custom module\n");

    if (nullptr == wl_global_create(compositor->wl_display, &greeting_interface, 1,
                     nullptr, bind_greeting)) {
        weston_log("my-custom-module: Failed to create global\n");
        return -1;
    }

    return 0;
}

}

bind_greeting()はクライアントがgreetingをバインドしたときに呼び出される関数。
wl_resource_create()でクライアントに対応するインスタンス(wl_resource)を生成し、greet()リクエストが呼び出されたときのコールバックをwl_resource_set_implementation()にて設定する。

done()イベントは関数として呼び出すだけで良い。(greeting_send_done()

module.cpp(抜粋)
void greet(struct wl_client *client,
           struct wl_resource *resource,
           const char *name)
{
    weston_log("Hello %s\n", name);

    greeting_send_done(resource);
}

static const struct greeting_interface greeting_impl = {
    .greet = greet
};

static void unbind_resource(wl_resource* resource)
{
}

static void bind_greeting(wl_client* client, void* data, uint32_t version, uint32_t id)
{
    weston_log("my-custom-module: bind_greeting\n");
    wl_resource* resource = wl_resource_create(client, &greeting_interface, version, id);

    wl_resource_set_implementation(resource, &greeting_impl, nullptr, unbind_resource);

}

課題:クライアント実装

この時点でgreeting.xmlを用いたクライアントを実装することができる。

前回を参考に、実際にクライアントを実装し動作を確認しよう。

実行例:

クライアントを実行すると

$ ./greeting-client Taro

Westonのログに以下のように表示されるはずである。

[12:48:59.066] Hello Taro

C/C++初級者への課題

課題

  • Westonがモジュールを呼び出している箇所をソースコード上で確認する
  • wet_module_init()にはなぜextern "C"が必要なのか、他の関数等に不要なのはなぜか
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?