Windows + MinGW + MSYS2でRust実装のPythonライブラリーを作る
はじめに
RustでPythonライブラリーを作成する手段としてPyO3があり、過去の記事「PyO3 + PoetryでPythonからRust実装を使う」でやり方を解説したが、暗黙的にLinuxやmacOSを対象としていた。
ライブラリーによってはWindows向けのWheel配布が必要なこともあるため、この記事ではGitHub Actionsを使ってWindows + MinGW + MSYS2環境でPyO3とRustを使ったPythonライブラリーのビルド方法について述べる。
この記事で利用するコードは下記のGitHubリポジトリーでまとめて公開している。
GitHub Actionsの設定
さっそくGitHub Actionsの設定を解説する。ただし次のようなmatrix
が定義されているものとする。
名前 | 意味 |
---|---|
msystem |
MSYS2のシステムでMINGW64 など[1]
|
arch |
MSYS2でインストールする依存のアーキテクチャーでx86_64 やaarch64 など |
path |
MinGWがインストールされているファイルパスでmingw64 など |
rust_target |
Rustのコンパイルターゲットでx86_64-pc-windows-gnu やx86_64-pc-windows-msvc
|
なお最終的なGitHub Actionsの設定は下記にある。
1. MSYS2をインストール
msys2/setup-msys2
を使うことで簡単にGitHub ActionsのWindowsにMSYS2をインストールできる。今回は最終的にPythonライブラリーを作るのが目的なため、Python関連のライブラリーをインストールしておく必要がある。ただしRustはこのあとの手順で公式のRustupからインストールするため、ここでインストールしなくてもよい。
- name: Install msys2 and dependencies
uses: msys2/setup-msys2@v2
with:
update: true
path-type: inherit
msystem: ${{ matrix.msystem }}
install: >-
mingw-w64-${{ matrix.arch }}-toolchain
mingw-w64-${{ matrix.arch }}-python
mingw-w64-${{ matrix.arch }}-cython
mingw-w64-${{ matrix.arch }}-python-pip
mingw-w64-${{ matrix.arch }}-python-poetry
mingw-w64-${{ matrix.arch }}-python-maturin
注意として、path-type: inherit
としてPATH
環境変数のアップデートがグローバルに適用されるようにしておく。またcython
やtoolchain
をインストールしておかないとPyO3まわりでエラーになってしまうので、これらも必要となる。
また今回はPoetryを使うのでpython-poetry
もインストールしておく。
2. MSYS2をデフォルトシェルに設定
GitHub Actionsは実行をWindows(windows-latest
)にした場合、pwsh
(PowerShell Core)がデフォルトで利用される。今回はMSYS2を使っていくため下記のような設定でmsys2
をデフォルトにする。
jobs:
test-mingw:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
3. RustupをMSYS2環境にインストール
RustをGithub Actionsにインストールする場合、たとえばdtolnay/rust-toolchain
といった便利なツールがある。しかしこれらのツールではシェルとしてbash
を指定している[2]ため、MSYS2環境を徹頭徹尾使うという方針に反してしまう。よって次のように手動でwin.rustup.rsからインストーラーのEXEファイルをダウンロードし、これでインストールする[3]。
- name: Install Rustup using win.rustup.rs
run: |
curl -o rustup-init.exe -sSL https://win.rustup.rs/
./rustup-init.exe -y --default-host=${{ matrix.rust_target }} --profile=minimal
rm rustup-init.exe
このときrustup-init.exe
がPATH
の設定をするので、最初で行ったMSYS2の設定path-type: inherit
が必要となる。あとはLinuxなどと同じく次のような手順でRustをインストールすればよい。
- name: Install Rust
run: |
rustup install stable --profile minimal
rustup default stable
rustup target add ${{ matrix.rust_target }}
poetry install
を実行
4. 今回はpoetry
を使うのでpoetry install
を行うが、SETUPTOOLS_USE_DISTUTILS=stdlib
という環境変数を設定してから行う必要がある。
- name: Install Poetry
run: |
export SETUPTOOLS_USE_DISTUTILS=stdlib
poetry install
この環境変数を設定せずにpoetry install
すると下記のようにmsgpack._cmsgpack
のインストールに失敗してしまう。
copying msgpack/__init__.py -> build/lib.mingw_x86_64-cpython-311/msgpack
running build_ext
building 'msgpack._cmsgpack' extension
error: --plat-name must be one of ('win32', 'win-amd64', 'win-arm32', 'win-arm64')
libpython
のシンボリックリンクを設定
5. 場合によっては(C言語のネイティブコードがあるとか?🤔)libpython
のシンボリックリンクの設定をしておかないと下記のようなコンパイルエラーになってしまう。
= note: C:/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lpython3.11: No such file or directory
collect2.exe: error: ld returned 1 exit status
よって、次のようなlibpython
のシンボリックリンク設定をしておく必要がある[4]。
- name: Create libpython symlink
run: ln -s /${{ matrix.path }}/lib/libpython3.11.dll.a /${{ matrix.path }}/lib/libpython311.dll.a
6. PyO3ライブラリーのコンパイル + Wheel作成
あとは過去記事PyO3 + PoetryでPythonからRust実装を使うなどの通りpoetry run maturin build
などでWheel作成などを行うことができる。
まとめ
環境変数SETUPTOOLS_USE_DISTUTILS
を設定したりlibpython
のシンボリックリンクを作成したりと、普段はあまりWindowsを使わない筆者からすると謎な手順が多い。もしかしたらもっとストレートフォワードな手順があるのかもしれないが、とりあえず現状これで上手くいったので記事にしておく。
-
たとえばここで
bash
を指定している👉 https://github.com/dtolnay/rust-toolchain/blob/21dc36fb71dd22e3317045c0c31a3f4249868b17/action.yml#L74 ↩︎ -
この
rustup-init.exe
を使う方法はRustupのWindows向けCIを参考にした。 ↩︎ -
この設定は
setuptools_rust
のWindows向けのCIを参考にした。 ↩︎
Discussion