使用Github Actions构建适用于Windows的Wheel文件
我正在维护一个名为mysqlclient的Python客户端库,它使用libmysqlclient。
这个库为 Windows 用户提供了一个静态链接的 Binary Wheel,可以使他们更容易地使用 libmysqlclient。我尝试使用 Github Actions 来自动构建这个 Binary Wheel。
如果是Github Actions的初学者,可能还有更好的方法,但如果对其他人有所帮助的话。
我的印象首先,我会先写下我的印象。虽然我在其他项目中已经使用AppVeyor自动构建了Windows上的Wheel,但这次的体验比之前的舒适多了。
-
VM起動が早い — AppVeyor に比べて push してからVMが立ち上がるまでの時間が圧倒的に短いように感じました。 AppVeyor を使っていたときは push するたびに数分待っていたのですが、 Github Actions ではサクサクと試行錯誤することができました。
- VM起動が早い — AppVeyor に比べて push してからVMが立ち上がるまでの時間が圧倒的に短いように感じました。 AppVeyor を使っていたときは push するたびに数分待っていたのですが、 Github Actions ではサクサクと試行錯誤することができました。
-
- Cache 万歳 — 今回はビルドに数分かかる依存ライブラリがあったのですが、それをcacheすることで本体の試行錯誤をサクサクと進めることができました。
-
- step ごとに違うシェルを選べる — cmd, PowerShell, そして Git for Windows の bash を、 step ごとに選択して書くことができます。 cmd や PowerShell には慣れていないので、どうやるのか迷った時にすぐに bash に逃げれるのは楽でした。
- Artifact が楽 — ビルドした Wheel を Artifact として登録し、ダウンロードすることができます。これは AppVeyor でもできたのですが、Github Actionsの方がダウンロードするまでも楽ですし、zip化されているので複数のファイルを1つずつダウンロードしなくていいのも楽だと思います。

准备用于构建的仓库为了避免污染库本体的存储库,我创建了一个名为mysqlclient-build的用于构建的另一个存储库,并在那里进行试错。这样可以在不破坏库存储库的情况下进行试错。
name: Build windows wheels
on:
push:
branches:
- master
create:
name: Build windows wheels
on:
push:
branches:
- master
create:
尽管后续会提到,但是由于此操作会对检出的目录产生影响,可能会有些麻烦。因此,我觉得在库本身仓库中的拉取请求中进行试错也是可行的选择。
构建依赖库
mysqlclient 使用 libmysqlclient,但在 Windows 的 Wheel 中使用的是 MariaDB Connector/C,它与 MySQL Connector/C 兼容。
这是因为它可以构建为使用 Windows 的 API 而不是 OpenSSL 进行与 MySQL 的 SSL 连接、caching_sha2_password 的 SHA256 计算等操作,并适用于静态链接的二进制文件分发。
然而,MariaDB Connector/C的二进制发行版中,认证等插件是以DLL的形式存在的。如果可能的话,我想要将其打包成单一二进制文件,所以我会自己构建MariaDB Connector/C。
由于每次构建mysqlclient时构建这个依赖库会花费很长时间,所以我们使用缓存操作。缓存操作会在作业成功时将指定目录缓存起来,所以我们将构建到MariaDB Connector/C的状态提交并成功后进行缓存。这样,在尝试构建mysqlclient时,我们可以利用已经构建好的MariaDB Connector/C。
jobs:
build:
runs-on: windows-latest
env:
CONNECTOR_VERSION: "3.1.5"
steps:
- name: Cache Connector
id: cache-connector
uses: actions/cache@v1
with:
path: c:/mariadb-connector
key: mariadb-connector-3.1.5-win
- name: Download and Unzip Connector
if: steps.cache-connector.outputs.cache-hit != 'true'
shell: bash
run: |
curl -LO "https://downloads.mariadb.com/Connectors/c/connector-c-${CONNECTOR_VERSION}/mariadb-connector-c-${CONNECTOR_VERSION}-src.zip"
unzip "mariadb-connector-c-${CONNECTOR_VERSION}-src.zip" -d c:/
mv "c:/mariadb-connector-c-${CONNECTOR_VERSION}-src" c:/mariadb-connector-src
- name: Build Connector
if: steps.cache-connector.outputs.cache-hit != 'true'
shell: cmd
working-directory: c:/mariadb-connector-src
run: |
mkdir build
cd build
cmake -A x64 .. -DCMAKE_BUILD_TYPE=Release -DCLIENT_PLUGIN_DIALOG=static -DCLIENT_PLUGIN_SHA256_PASSWORD=static -DCLIENT_PLUGIN_CACHING_SHA2_PASSWORD=static
cmake --build . -j 8 --config Release
cmake -DCMAKE_INSTALL_PREFIX=c:/mariadb-connector -DCMAKE_INSTALL_COMPONENT=Development -DCMAKE_BUILD_TYPE=Release -P cmake_install.cmake
将mysqlclient进行构建
首先,在 checkout 操作中,我们会 checkout mysqlclient。默认情况下,会将工作目录 checkout 到包含 workflow 的存储库(在本例中为 mysqlclient-build),但是我们可以使用 with: 来将其他存储库 checkout 到另一个路径。
在这里有一个陷阱,如果您在 path: mysqlclient 中进行检出,检出的目标将不是 ./mysqlclient,而是 ../mysqlclient。默认的工作目录是用于检出该存储库的目录,当要检出另一个存储库时,应该在其旁边创建一个目录进行检出,而不是在其下面。因此,在检出后的步骤中,我们指定 working-directory: ../mysqlclient。
在构建完成后,可以使用名为upload-artifact的操作将wheel文件上传到Github,然后确保能够实际安装并通过导入进行使用。
如果可能的话,我本来想进行测试直到操作完成,但由于Windows-latest上未安装MySQL Server,所以这次没有进行。因为可以使用Docker,所以我会尝试使用Docker来安装MySQL Server并在将来尝试。
- name: Checkout mysqlclient
uses: actions/checkout@v1
with:
repository: PyMySQL/mysqlclient-python
ref: master
fetch-depth: 10
path: mysqlclient
- name: Site Config
shell: bash
working-directory: ../mysqlclient
run: |
pwd
find .
cat <<EOF >site.cfg
[options]
static = True
connector = C:/mariadb-connector
EOF
cat site.cfg
- name: Build wheels
shell: cmd
working-directory: ../mysqlclient
run: |
py -3.8 -m pip install -U setuptools wheel pip
py -3.8 setup.py bdist_wheel
py -3.7 -m pip install -U setuptools wheel pip
py -3.7 setup.py bdist_wheel
py -3.6 -m pip install -U setuptools wheel pip
py -3.6 setup.py bdist_wheel
- name: Upload Wheel
uses: actions/upload-artifact@v1
with:
name: win-wheels
path: ../mysqlclient/dist
- name: Check wheels
shell: bash
working-directory: ../mysqlclient/dist
run: |
ls -la
py -3.8 -m pip install mysqlclient-1.4.6-cp38-cp38-win_amd64.whl
py -3.8 -c "import MySQLdb"
py -3.7 -m pip install mysqlclient-1.4.6-cp37-cp37m-win_amd64.whl
py -3.7 -c "import MySQLdb"
py -3.6 -m pip install mysqlclient-1.4.6-cp36-cp36m-win_amd64.whl
py -3.6 -c "import MySQLdb"