Appveyor による Windows サポート

Page Status:Incomplete
Last Reviewed:2015-12-03

このセクションでは、無料の Appveyor 継続的インテグレーションサービスを使ってプロジェクトの Windows サポートを提供する方法を説明する。これには、Windows 上でのコードのテスト、およびプロジェクトが C 拡張を使う場合の Windows 用バイナリのビルドが含まれる。

背景

多くのプロジェクトはデフォルトでは Unix 上で開発されており、Windows サポートの提供は難しいことがある。というのは、Windows テスト環境を適切に構築するのは面倒だし、ソフトウェアライセンスの購入が必要かもしれないからだ。

Appveyor サービスは継続的インテグレーションサービスで、より有名な Travis サービス(Github でホストされたプロジェクトがよくテストに使っている)によく似ている。しかし Travis と異なり、Appveyor のビルドワーカーは Windows ホストであり、Python 拡張のビルドに必要なコンパイラがインストール済みだ。

Windows ユーザは C コンパイラを持っていないのが普通なので、彼らが C 拡張を使うプロジェクトを pip install <dist> でインストールするには、プロジェクト側で配布する PyPI 上のバイナリ wheel に頼ることになる。 Appveyor をビルドサービスとして使うと(テストには使わなくても)、プロジェクトが専用の Windows 環境なしで Windows バイナリを提供できるようになる。

セットアップ

プロジェクトで Appveyor を使って Windows 用 wheels をビルドするには、サービスのアカウントを作る必要がある。アカウント取得の手順は Appveyor ドキュメント にある。オープンソースプロジェクトなら、無料版アカウントで全く問題ない。

Appveyor には Github および Bitbucket との統合機能があるので、プロジェクトがこれら 2 つのサービスのいずれかでホストされているなら、 Appveyor との統合は簡単だ。

Appveyor アカウントを取得してプロジェクトを追加すると、Appveyor はコミットのたびにプロジェクトを自動ビルドするようになる。この動作は Travis ユーザにはおなじみのものだろう。

プロジェクトに Appveyor サポートを追加する

Appveyor がプロジェクトをビルドする方法を定義するには、プロジェクトに appveyor.yml ファイルを追加する。このファイルの内容の完全な詳細は Appveyor ドキュメントにある。このガイドでは wheel のビルド設定に必要な部分を詳しく説明する。

Appveyor にはデフォルトで Python 用拡張のビルドに必要な全てのコンパイラツールチェインが含まれている。これらは Python 2.7, 3.5+ および 32-bit 版の 3.3, 3.4 に対してはそのままで使える。しかし 64-bit 版の Python 3.3, 3.4 の場合、少々の追加設定を行って distutils に 64-bit コンパイラの場所を知らせる必要がある (3.5 以降では、使用するバージョンの Visual Studio は追加設定なしで 64-bit コンパイラを含む)。

appveyor.yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
environment:

  matrix:

    # For Python versions available on Appveyor, see
    # http://www.appveyor.com/docs/installed-software#python
    # The list here is complete (excluding Python 2.6, which
    # isn't covered by this document) at the time of writing.

    - PYTHON: "C:\\Python27"
    - PYTHON: "C:\\Python33"
    - PYTHON: "C:\\Python34"
    - PYTHON: "C:\\Python35"
    - PYTHON: "C:\\Python27-x64"
    - PYTHON: "C:\\Python33-x64"
      DISTUTILS_USE_SDK: "1"
    - PYTHON: "C:\\Python34-x64"
      DISTUTILS_USE_SDK: "1"
    - PYTHON: "C:\\Python35-x64"

install:
  # We need wheel installed to build wheels
  - "%PYTHON%\\python.exe -m pip install wheel"

build: off

test_script:
  # Put your test command here.
  # If you don't need to build C extensions on 64-bit Python 3.3 or 3.4,
  # you can remove "build.cmd" from the front of the command, as it's
  # only needed to support those cases.
  # Note that you must use the environment variable %PYTHON% to refer to
  # the interpreter you're using - Appveyor does not do anything special
  # to put the Python evrsion you want to use on PATH.
  - "build.cmd %PYTHON%\\python.exe setup.py test"

after_test:
  # This step builds your wheels.
  # Again, you only need build.cmd if you're building C extensions for
  # 64-bit Python 3.3/3.4. And you need to use %PYTHON% to get the correct
  # interpreter
  - "build.cmd %PYTHON%\\python.exe setup.py bdist_wheel"

artifacts:
  # bdist_wheel puts your built wheel in the dist directory
  - path: dist\*

#on_success:
#  You can use this step to upload your artifacts to a public website.
#  See Appveyor's documentation for more details. Or you can simply
#  access your wheels from the Appveyor "artifacts" tab for your build.

このファイルは ここ からダウンロードできる。

appveyor.yml ファイルはプロジェクトのルートディレクトリに置かねばならない。これは YAML 形式で、いくつかのセクションから成る。

environments セクションは作成される wheels に対する Python バージョンを定義する鍵となるものだ。Appveyor には Python 2.6, 2.7, 3.3, 3.4, 3.5 が(全て 32-bit, 64-bit の両方)インストールされている。サンプルファイルでは、Python 2.6 を除く全ての環境用にビルドするよう指定している。Python 2.6 には pip が付属していないので、インストールがより複雑になる。この文書では 2.6 はサポートしない(まだ Python 2 を使っている Windows ユーザは、普通大した困難なく Python 2.7 へ移行できるので)。

install セクションでは、pip を使ってプロジェクトに必要な追加ソフトウェアをインストールしている。Wheels のビルドに必要なのは wheel だけだが、プロジェクトでこのコードをカスタマイズしたい場合もあるかもしれない(例えば、 Cython のようなビルドパッケージや、 tox のようなテストツールを追加でインストールするとき)。

build セクションでは単にビルドをオフにしている - Python にビルドステップは必要ない (C# のような言語と違って)。

プロジェクトごとに調整する必要がある主なセクションは test_scriptafter_test だ。

test_script セクションでプロジェクトのテストを実行する。build.cmd スクリプトが setup.py test でテストスイートを実行する。Wheels のビルドのみに興味があり、Windows 上でテストを行うつもりがないなら、このセクションを echo Skipped Tests のようなダミーコマンドで置き換えてもよい。テストツールとして nosepy.test などを使いたいこともあるかもしれない。あるいは tox のようなテストドライバを使いたいこともあるかもしれない - ただし tox を使う場合、以下で説明するようにいくつか追加の設定変更を考慮する必要があるだろう。

after_test はテスト完了後に一回だけ実行される。つまりここで wheels がビルドされる。プロジェクトが推奨ツール(特に setuptools) を使っていれば、 setup.py bdist_wheel コマンドで wheels がビルドされる。

Wheels はテストが成功した場合のみビルドされることに注意。Windows 上ではテストが失敗するとわかっているなら、上記のようにテストをスキップできる。

サポートスクリプト

appveyor.yml ファイルは一つのサポートスクリプトに依存している。このスクリプトは 64-bit Python 3.3, 3.4 用に SDK コンパイラを使うための環境構築を行う。プロジェクトがコンパイラを必要としないか、64-bit Windows 上の Python 3.3, 3.4 をサポートしないなら、必要なのは appveyor.yml ファイルだけだ。

build.cmd は Windows バッチスクリプトで、選択した Python バージョンに対して適切なコンパイラを使う環境で単一のコマンドを実行する。必要なのは環境変数 DISTUTILS_USE_SDK に値 1 を設定することだけで、残りはこのスクリプトが行う。これは 64-bit Python 3.3, 3.4 に必要な SDK を設定するという意味なので、他の Python ビルドに対してはこの環境変数を設定しないこと。

上記のバッチファイルをダウンロードしてプロジェクトにそのまま含めてよい。

ビルドされた wheels へのアクセス

ビルドが完了すると、プロジェクトの Appveyor コントロールパネルからビルドされた wheels が取得できる。各ビルドのビルドステータスページを順に辿ることで見つけられる。ビルド出力の上部にリンクが並んでおり、 “Artifacts” というものがある。そのページには当該 Python バージョン/ アーキテクチャ用の wheels へのリンク一覧がある。これらの wheels をダウンロードし、リリースプロセスの一環として PyPI へアップロードできる。

Additional Notes

Tox を用いたテスト

多くのプロジェクトがテストの実行に Tox ツールを使っている。これはプロジェクトが配布するのと全く同じファイルを使う隔離環境でテストが実行されることを保証する。

Appveyor で tox を使うには、いくつか追加の考慮事項がある(実際のところ、これらは Appveyor 固有の問題ではなく、他の CI システムにも影響しうる)。

  1. デフォルトでは、 tox は環境変数のうち選択されたサブセットのみをテストプロセスに渡す。 distutils は環境変数を使ってコンパイラを制御しているので、この「テスト隔離」機能により誤ったコンパイラがデフォルトで使われてしまうことがある。

    tox が必要な環境変数をサブプロセスに渡すようにするには、 tox 構成オプション passenv を設定し、サブプロセスに渡すべき追加の環境変数リストを与える必要がある。SDK コンパイラを使う場合、以下を設定する:

    • DISTUTILS_USE_SDK
    • MSSdk
    • INCLUDE
    • LIB

    passenv オプションは tox.ini で設定できるが、プロジェクトファイル群に Windows 固有設定を加えるのを避けたければ、 TOX_TESTENV_PASSENV 環境変数を設定してもよい。先に示した build.cmd スクリプトは DISTUTILS_USE_SDK がセットされていればデフォルトでこれを行う。

  2. 対話的に使う場合、 tox は複数の環境(しばしば複数の Python バージョンを意味する)に対してテストを実行できる。この機能は Travis や Appveyor のような CI 環境ではさほど有用ではない。なぜなら全テストは個別の構成に対して隔離環境で実行されるからだ。結果として、プロジェクトはしばしば -e ENVNAME 引数を tox に与えて使う環境を指定することになる(ほとんどの Python バージョンに対してはデフォルトの環境があるので)。

    しかし、この方法は Appveyor のような Windows CI システムではうまく いかない 。例えば Python 3.4 の環境が 2 つ(32-bit と 64-bit) あるが、 tox には py34 環境 1 つしかない、といった場合だ。

    従って、 tox を使ってテストを実行するには、プロジェクトはおそらく tox 内ではデフォルトの py 環境を使うべきだ。この環境は tox の実行に使われたのと同じ Python インタプリタを使う。これにより、Appveyor がテストを実行する際、設定されたインタプリタで実行されることが保証される。

    py 環境での実行をサポートするために、複雑な tox 構成を持つプロジェクトは tox.ini ファイルを修正しなければならない可能性がある。しかしこれはこの文書の範囲外だ。

Wheels の自動アップロード

Appveyor が自動で wheels をアップロードするように要求できる。 appveyor.yml には deployment ステップがあり、例えばビルド結果を FTP サイトや Amazon S3 インスタンスにコピーしたりできる。これを行う方法は Appveyor ガイドに含まれている。

代わりに、ビルドに twine upload ステップを追加することもできる。先に示した appveyor.yml ではこれを行っていない。なぜならコミットのたびに新しい wheels をアップロードするのが望ましいかどうかはわからないからだ(プロジェクトによってはそうしたいと思うかもしれないが)。

外部依存関係

先に示したスクリプトは、ビルドの際にサードパーティの外部ライブラリに依存しない任意の distribution をビルドできる。

appveyor.yml 構成(普通は “install” セクション内)に distribution が必要とする外部ライブラリをダウンロード/ビルドするステップを加えることができる。また、必要ならこれらのライブラリの場所をコンパイラに知らせるためのビルド用構成を追加することもできる。しかし、このレベルの構成はこの文書の範囲外だ。

サポートスクリプト

参考までに、SDK 設定用サポートスクリプトを掲載する:

code/build.cmd

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
@echo off
:: To build extensions for 64 bit Python 3, we need to configure environment
:: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of:
:: MS Windows SDK for Windows 7 and .NET Framework 4
::
:: More details at:
:: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows

IF "%DISTUTILS_USE_SDK%"=="1" (
    ECHO Configuring environment to build with MSVC on a 64bit architecture
    ECHO Using Windows SDK 7.1
    "C:\Program Files\Microsoft SDKs\Windows\v7.1\Setup\WindowsSdkVer.exe" -q -version:v7.1
    CALL "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 /release
    SET MSSdk=1
    REM Need the following to allow tox to see the SDK compiler
    SET TOX_TESTENV_PASSENV=DISTUTILS_USE_SDK MSSdk INCLUDE LIB
) ELSE (
    ECHO Using default MSVC build environment
)

CALL %*