1
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?

More than 1 year has passed since last update.

Windows上の Python-3.11 で動く Gtk4 や GStreamer をビルドする

Last updated at Posted at 2022-11-13

試行錯誤の結果、ビルド手順を編み出した。

MSYS, MINGW は使わずに MSVC だけで完結させる例です。

環境と関連ツールのインストール

インストール先のフォルダを決めて prefix と呼びます。
C:\gnome にしました。

  • Windows11(64bit)
  • vc build tool 2022
  • python-3.11 => C:/Python311
    • pip install meson => C:/Python311/Scripts/meson.exe
  • cmake-3.22.1(Android SDK のやつにパス通した。meson が使っている?無くても動くかも)
  • ninja(Android SDK の cmake と同じパスに入っているやつ)
  • win_flex win_flex_bison3-latest.zip パス通す
  • pkg-config lite パス通す
    • 環境変数 PKG_CONFIG_PATH を設定。場所は prefix + lib\pkgconfig

最初からやり直すときは

C:/gnome (prefix)
pygobject/build
gtk/build
gstreamer/build

を削除してください。
完全に掃除するには、

pygobject/subprojects
gtk/subprojects
gstreamer/subprojects

の clone されたりアーカイブが解凍されたフォルダも消してください。

meson の subprojects

最近の GTK 周りではビルドに meson が使われています。
meson には、システムのライブラリ(zlibなど)をサーチ(pkg-config)して見つかればそれを使うし、
なければダウンロードして自前でビルドするという機能が備わっています。

https://mesonbuild.com/Wrapdb-projects.html

A + subproject B という構成があったときに、
以下の2つで、わりと異なる結果になります。

install A(subproject B を自動インストール)
install B
install A

そのためインストール順によって、うまくいったりいかなかったりしました。

PYTHONUTF8 とロケールの組み合わせ

Windows11(64bit) + python-3.11で実験

環境変数 PYTHONUTF8=1 日本語Windowsの utf-8 ロケール
あり あり 動く
あり なし UnicodeDecodeError
なし なし 動く
なし あり 試していない

ロケール周りの挙動

PYTHONUTF8=1 で subprocess 系の挙動が変わる。
一方、日本語Windowsの utf-8 ロケールで VC のマルチバイト文字列のエンコーディングの挙動が変わる。

C:/Python311/Lib/locale.py
    def getpreferredencoding(do_setlocale=True):
        """Return the charset that the user is likely using,
        according to the system configuration."""

        if sys.flags.warn_default_encoding:
            import warnings
            warnings.warn(
                "UTF-8 Mode affects locale.getpreferredencoding(). Consider locale.getencoding() instead.",
                EncodingWarning, 2)
        if sys.flags.utf8_mode: # 👈 環境変数 PYTHONUTF8 と連動?
            return 'utf-8'

設定が一致しないと meson が pipe 経由でコンパイラ等を操作したときに例外が発生します。

UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8e in position 115: invalid start byte

ビルド

本記事では、

  • pygobject(GLib, gobject-introspection etc...)
  • gtk(cairo, gtk, gdk etc...)
  • gstreamer

という順でインストールします。

pygobject

初手で pygobject

何故か cairo -> pygobject のように subproject を分けるとビルドがうまくいかない。
例えビルドできても python から GLib を参照したときに型情報の取得に失敗したりする。
初手で pyproject にするとうまくいく。
pyproject -> gobject-introspection -> glib という subproject 連鎖の
どこかに違いがありそう。

> git clone https://gitlab.gnome.org/GNOME/pygobject.git
> cd pygobject
pygobject> meson setup build --prefix C:/gnome -Dpycairo=disabled -Dtests=false
pygobject> meson compile -C build # make のように省略可
pygobject> meson install -C build

pygobject エラー対応

ImportError: DLL load failed while importing _giscanner: 指定されたモジュールが見つかりません

python-3.7 以前ではこの手順は不要です。

Windows版 python-3.8 の動的ライブラリの挙動変更

これは native module のロードが失敗するというかたちで現れます。

What’s New In Python 3.8 — Python 3.8.14 documentation

PATH and the current working directory are no longer used

環境変数 GI_EXTRA_BASE_DLL_DIRS に関連する dll のディレクトリを指定してやればよい。

本来ならば C:/gnome/bin に配置される dll が、まだビルドしたけどインストールしていないので build フォルダに存在している

dll をサーチして、そのフォルダを ";" で連結した文字列を作る python スクリプト例。

dll_dir.py
import pathlib
from typing import List

HERE = pathlib.Path(__file__).absolute().parent

class DllAggregator:
    def __init__(self) -> None:
        self.dll_list: List[pathlib.Path]=[]

    def process(self, path: pathlib.Path):
        for e in path.iterdir():
            if e.is_dir():
                self.process(e)
            elif e.suffix.lower() == '.dll':
                self.dll_list.append(e)


if __name__ == '__main__':
    dll_list = DllAggregator()
    dll_list.process(HERE)

    dir_list=[]
    for e in dll_list.dll_list:
        if e.parent not in dir_list:
            dir_list.append(e.parent)

    print(';'.join(str(e) for e in dir_list))

power shell で環境変数をセットする例

$env:GI_EXTRA_BASE_DLL_DIRS="C:/path/to/build/hoge;C:/path/to/build/fuga" # python の os.add_dll_directory に渡る。たぶん "/" と "\" どちらでも動く。

pygobject 動作確認

pth ファイルで c:/gnome/lib/site-packages を追加する

c:/python311/lib/site-packages/gi.pth
c:/gnome/lib/site-packages

もしくは環境変数

PYTHONPATH=c:/gnome/lib/site-packages
import gi
gi.require_version('GLib', '2.0')
from gi.repository import GLib # うまくインストールされていないとここでエラーになる。 assert g_type != TYPE_NONE
print(GLib.MainLoop)

DLL load failed while importing _gi: 指定されたモジュールが見つかりません。

python-3.8 以降向け
nativie モジュールを import する前の行にハードコーディングします。

C:\gnome\lib\site-packages\gi__init__.py
os.add_dll_directory('C:/gnome/bin') # python-3.8 以降で必要
from . import _gi

エラーが出なければ OK。

gtk4

$ git clone https://github.com/GNOME/gtk.git
$ cd gtk
gtk$ meson setup build --prefix C:/gnome -Dmedia-gstreamer=disabled -Dbuild-tests=false
gtk$ meson install -C build

gtk4 動作確認

import gi
gi.require_version('Gtk', '4.0') # 👈 4.0
from gi.repository import Gtk

エラーが出なければインストールできているはず。
以上で Python-3.11 + Gtk4 成功です。

gtk3

gtk-3 も問題なくビルドできて gtk-4 と共存できた。
3系の最新版 gtk-3.24 を入手。

解凍してビルド。

> meson setup build --prefix C:/gnome
> meson install -C build

gtk3 エラー対応

Couldn't find include 'Atk-1.0.gir'

途中 Atk の gir が見つからないというエラーが出て止まる。
Atk を先に入れる。

meson により、gtk-3 のビルド過程で subprojects/atk.wrap により subprojects/atk にソースが展開されています。

> cd subprojects/atk
subprojects/atk> meson setup build --prefix C:/gnome
subprojects/atk> meson install -C build

元のフォルダに戻る。続きを実行。

> meson install -C build

gtk3 動作確認

import gi
gi.require_version('Gtk', '3.0') # 👈 3.0
from gi.repository import Gtk

gstreamer

ビルド済みの gstreamer と比べて、 dshow 系の elment が増えるので Windows ではビルドすると使い勝手が良くなる。

gstreamer エラー対応

dshowvideosink.cpp でコンパイルエラー

適当に cast してあげる。

      SendMessage (previous_window, WM_CLOSE, (WPARAM)NULL, (LPARAM)NULL);
    SystemParametersInfo (SPI_GETWORKAREA, (UINT)NULL, &rect, 0);
    SendMessage (sink->window_id, WM_CLOSE, (WPARAM)NULL, (LPARAM)NULL);

gstreamer 動作確認

import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst
Gst.init(None)

Vala 言語

fork して CMakeLists.txt 改造。
オリジナルが vala-0.48 向けだったのだけど、
新しい vala-0.56 でもそのまま動いてしまった。

TODO: cmake を meson 化する

上記でビルドした glib, gobject-introspection に対してビルドできた。

valac --version
Vala 0.56.3

動くかな?

libadwaita ビルドできなかった。ちゃんと動いていない。

その他のエラー対応

TypeError: Couldn't find foreign struct converter for 'cairo.Context'

pycairo が入っていない。
cairo の後で pygobject をインストールすることでインストールされる。

pygobject> rm build
pygobject> meson setup build --prefix c:/gnome
pygobject> meson install -C build

エラー発生

FileNotFoundError: [WinError 2] 指定されたファイルが見つかりません。: 'C:\\ghq\\github.com\\GNOME\\pygobject/build\\subprojects\\proxy-libintl'

# 消し忘れ。環境変数クリア。
$env:GI_EXTRA_BASE_DLL_DIRS=""

referenced by the typelib: 'cairo-gobject.dll': 指定されたモジュールが見つかりません。

cairo-gobject-2.dll ?

インストール順

行きつ戻りつしつつ同じライブラリのスキップされた要素を再インストールしていくこともある。

  • gobject-introspection > glib
  • pygobject > cairo, gobject-introspection
  • gtk > cairo, gobject-introspection
  • gst-python > gobject-introspection
  • gtk の media-gstreamer > gstreamer

subproject の個別インストールと順番の調整は改善の余地あり。

依存関係を考慮して meson の呼び出しを制御するツールを作ったほうがいいかもしれない。
clone, patch, meson を繰り返す。

meson のデバッグ実行

python なのでデバッガをアタッチできる。
vscode の設定例。

.vscode/settings.json
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "meson",
            "type": "python",
            "request": "launch",
            "module": "mesonbuild.mesonmain", // 👈 meson モジュールのエントリーポイント
            "args": [
                "setup", // 👈 作業で使いたい引数を指定する
                "build",
                "--prefix",
                "c:/gnome"
            ],
            "cwd": "${workspaceFolder}",
            "justMyCode": false // 👈 重要。.venv の中で break できる
        },
    ]
}

venv に meson 入れる

meson 自体に手を入れたり、print debug する際に。

> py -m venv .venv
> .venv/Scripts/Activate.ps1
(.venv)> pip install meson

参考

続編

1
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
1
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?