試行錯誤の結果、ビルド手順を編み出した。
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
- pip install meson =>
- 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
- 環境変数 PKG_CONFIG_PATH を設定。場所は
最初からやり直すときは
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 のマルチバイト文字列のエンコーディングの挙動が変わる。
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
andthe current working directory
are no longer used
環境変数 GI_EXTRA_BASE_DLL_DIRS
に関連する dll のディレクトリを指定してやればよい。
本来ならば C:/gnome/bin に配置される dll が、まだビルドしたけどインストールしていないので build フォルダに存在している
dll をサーチして、そのフォルダを ";" で連結した文字列を作る python スクリプト例。
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:/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 する前の行にハードコーディングします。
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 の設定例。
{
// 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
参考
続編