6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

cibuildwheel で python bwheel(C++ モジュール含む) を CI で一括ビルドし PyPI へアップロードするメモ

Last updated at Posted at 2020-04-26

漢なら Python pip で Windows, macOS, Linux で C++ モジュール含んだ prebuilt wheel インストールしたいですね!

cibuildwheel でやりましょう!

いろんな環境と python バージョンでビルドしてくれるスクリプトです. 素晴らしいですね.
これを自前プロジェクトの CI(travis, GitHub Actions, etc)に取り込めばいいです.

ちょっとわかりずらいですが,

$ python3 -m cibuildwheel --output-dir wheelhouse

を実行することで, python setup.py bdist_wheel 相当を, それぞれの python バージョンの環境を構築して実行してくれます
(Linux, macOS の場合は Docker 利用).

ビルド前にスクリプトを実行する

cibuildwheel では, Linux, macOS ですと Docker コンテナで実行されるため, Travis などで CI ビルドを行う場合は, git submodule update みたいなのは docker コンテナの内部で実行しないといけません.

cibuildwheel の環境変数で, いくつか設定することができます.

ARM64 対応

ありがとうございます.

Github Actions ですと, Linux での arm64 ビルドは qemu になり遅いです.
Cirrus CI を使うとよいでしょう.

Windows ですと, cross-compile での対応になります(test は走らせられない).
また, x86 のビルドと混在すると, x86 ビルドで残っている .obj キャッシュを参照するようになりビルド(リンク)がこけます.

ビルドごとに毎回ビルドキャッシュを clean するのがよいでしょうが, とりあえずは job を分けるのがよいでしょうか.
TinyUSDZ での例を参照ください.

pypi にアップロードする

PyPI に Linux バイナリでパッケージをアップロードするメモ
https://qiita.com/syoyo/items/6185380b8d9950b25561

あたりを参照ください

Github Actions では trusted publisher 推奨っぽい.

2023/12 月時点では, Github Actions で pypi にアップロードする場合, アクセストークン(Encrypted environment variable)ではなく, Trusted Publisher を使うのが推奨のようです.

要はアクセストークンだと無限期間有効でセキュリティの懸念があるので, 短期でのみ有効なトークン(15 分間だけ)を CI での upload 時に作成してセキュリティ高めましょうという感じです. 2023/12 時点では CI サービスは Github Actions のみの対応になっています.

Azure pipeline は...?

Azure pipeline だと, twine などでビルド後アップロード自動化は現状めんどそうですが, vispy の設定が参考になるでしょうか.

一応 template が提案されていたりしますが, いくつか制約などがある感じです.

実際 tinyobjloader で使ってみましたが, オンラインドキュメントがわかりづらく, Travis に比べて面倒な感じでした.
(yaml 記述はオンラインエディタで構文チェックできるのがよいですが)

Travis が使えるなら travis を使う(or Github actions)を推奨します.

ビルド and publish の流れ

  • OS ごとに cibuildwheel で whl ビルド
  • CopyFiles@2 で staging folder(ジョブが終わっても残っているディスク領域?)にビルド物をコピー
    • $(Build.ArtifactStagingDirectory) がステージングフォルダ
  • PublishBuildArtifacsts@0 で, artifact のフォルダに名前をつける
      - task: PublishBuildArtifacts@1
        inputs:
          path: $(Build.ArtifactStagingDirectory)
          artifactName: tinyobjDeployWindows

デプロイ(e.g. PyPI へのアップロード)では,
まず依存するタスクが完了しているか(dependsOn)と, tag コミットであることをチェックします.

  - job: deployPyPI
    # Based on vispy: https://github.com/vispy/vispy/blob/master/azure-pipelines.yml
    pool: {vmImage: 'Ubuntu-16.04'}
    condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
    dependsOn:
      - linux
      - macos
      - windows

その後, DownloadBuildArtifacts で, job のアーティファクト(実態としてはフォルダ群)をダウンロードします.

      - task: DownloadBuildArtifacts@0
        inputs:
          artifactName: 'tinyobjDeployWindows'
          downloadPath: $(Pipeline.Workspace)

このとき, artifactName でフォルダが作られ($(Pipeline.Workspace)/tinyobjDepoloyWinwdows), その中にビルド物が配置されます.
デバッグでは, ls などでログに出力して確認できるようにしておくとよさそうです.

あとは twine で publish して完成です!

      # Publish to PyPI through twine
      - bash: |
          cd $(Pipeline.Workspace)
          find .
          python -m pip install --upgrade pip
          pip install twine
          echo tinyobjDeployLinux/python/dist/*
          echo tinyobjDeployLinux/python/wheelhouse/* tinyobjDeployMacOS/python/wheelhouse/* tinyobjDeployWindows/python/wheelhouse/*
          twine upload -u "__token__" --skip-existing tinyobjDeployLinux/python/dist/* tinyobjDeployLinux/python/wheelhouse/* tinyobjDeployMacOS/python/wheelhouse/* tinyobjDeployWindows/python/wheelhouse/*
        env:
          TWINE_PASSWORD: $(pypiToken2)

TWINE のパスワード(シークレットトークン)は, pypiToken2 の名前で Azure Pipeline の website でシークレットトークンを variable で登録しておきます.

感想

毎回 git push してビルドトリガーして 10 分くらい待ち, エラーが出ると修正 & 再度 tag つけて push がめんどいので, 手元で試せる環境がほしいところです.

Twine token

Azure Pipeline でも, Twine(PyPi)のシークレットトークンを扱える secret variables の機能がありますので, そちらを利用できます.

Secret variable は, ビルドスクリプト内では環境変数経由で指定します.

PublishBuildArtifacts を使いましょう

PublishPipelineArtifactOne or more errors occurred というエラーメッセージにもなっていないログだけ出して(エラー理由がまったく表示されない)てうまくうごきません.

PublishBuildArtifacts を使いましょう.

C++ コードを含んだ実際のサンプル

cibuildwheel して, pypi アップロード,

pytinyexr(PyEXR) では Travis を使っています.

tinyobjloader では Azure Pipeline を使っています.

Py2.7(or pypy) + Windows + pybind11

少なくとも pypy はビルドエラーになるので, pp27-win32, pp36-win32 あたりは CIBW_SKIP に含めてビルドしないようにしておきましょう
(pypy 使っている人いるのだろうか?)

また, python2.7 + C++11 も基本は非推奨です.

py27 を使わなければならない強い理由がなければ, python 2.7 サポートはしないほうがいいでしょう.

TODO

  • GitHub Actions でのサンプルを作る
6
3
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
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?