Python wheel とは?ビルド済みアーティファクトの仕組みと実践的な使い方
Python のパッケージをインストールするとき、pip が裏で何を取得しているかを意識したことはあるか? wheel(.whl)はコンパイル済みのビルド成果物で、sdist(ソース配布)と比べてインストールが大幅に速い。本記事では wheel の構造・ファイル名の読み方・作り方・CI での活用まで実践的に整理する。
wheel とは
wheel(PEP 427 で定義)は ZIP 形式のアーカイブに .whl 拡張子を付けたビルド済み配布形式だ。pip install 時にビルドステップを一切実行せず、ファイルをコピーするだけでインストールが完了する。
sdist との違い
| 比較軸 | wheel (.whl) | sdist (.tar.gz) |
|---|---|---|
| インストール速度 | 速い(コピーのみ) | 遅い(ビルドが必要) |
| C コンパイラ不要 | ◎ | △(C 拡張があれば必要) |
| ソースコード含む | × | ○ |
| プラットフォーム依存 | あり(バイナリの場合) | なし |
| PyPI へのアップロード | ○ | ○ |
pip はパッケージ解決時に wheel を優先し、対応する wheel がなければ sdist にフォールバックする。
ファイル名の読み方
wheel のファイル名は以下の形式になっている。
{distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl
具体例:
numpy-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
│ │ │ │ └── プラットフォームタグ
│ │ │ └── ABI タグ(CPython 3.13 のバイナリ互換性)
│ │ └── Python タグ(cp313 = CPython 3.13)
│ └── バージョン
└── パッケージ名
代表的なタグ
| タグ | 意味 |
|---|---|
py3-none-any | Pure Python、Python 3 全般、全プラットフォーム |
cp313-cp313-win_amd64 | CPython 3.13、Windows 64bit |
cp312-cp312-manylinux_2_17_x86_64 | CPython 3.12、Linux x86_64(GLIBC 2.17+) |
cp311-abi3-linux_x86_64 | stable ABI(abi3)を使用、複数バージョンで動作 |
Pure Python パッケージ(C 拡張なし)は py3-none-any タグの ユニバーサル wheel を1つ公開すれば全環境をカバーできる。
wheel の内部構造
wheel は ZIP なので直接展開して確認できる。
unzip -l numpy-2.2.3-cp313-cp313-manylinux_2_17_x86_64.whl
中身のレイアウト:
numpy/ # 実際のパッケージコード
numpy-2.2.3.dist-info/
├── METADATA # パッケージメタデータ(PEP 658)
├── WHEEL # wheel 自身のメタデータ
├── RECORD # 全ファイルの SHA-256 ハッシュ
└── entry_points.txt # CLI コマンド定義(あれば)
WHEEL ファイルの中身例:
Wheel-Version: 1.0
Generator: bdist_wheel (0.45.1)
Root-Is-Purelib: false
Tag: cp313-cp313-manylinux_2_17_x86_64
Root-Is-Purelib: false はバイナリ wheel(platlib に展開)を示す。Pure Python は true。
wheel のビルド方法
1. build を使う(推奨)
pip install build
# sdist + wheel を同時生成
python -m build
# wheel のみ生成
python -m build --wheel
dist/ 以下に .whl と .tar.gz が生成される。
2. pyproject.toml の最小構成
# pyproject.toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "mypackage"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = ["requests>=2.31"]
ビルドバックエンドは hatchling、flit-core、setuptools など選択肢があるが、新規プロジェクトでは hatchling が設定シンプルでおすすめ。
3. C 拡張を含むパッケージ(scikit-build-core)
Cython や C/C++ 拡張を含む場合は scikit-build-core + CMake が主流になっている。
[build-system]
requires = ["scikit-build-core", "cython"]
build-backend = "scikit_build_core.build"
manylinux:Linux での配布可能な wheel
バイナリ wheel を Linux 向けに PyPI へアップロードするには manylinux 準拠が必要だ。ローカルでビルドした linux_x86_64 タグの wheel は PyPI にアップロードできない。
manylinux タグの世代
| タグ | 対応 GLIBC | 対応ディストリビューション目安 |
|---|---|---|
manylinux1 | 2.5 | CentOS 5 以降(廃止済) |
manylinux2010 | 2.12 | CentOS 6 以降(廃止済) |
manylinux2014 / manylinux_2_17 | 2.17 | CentOS 7 以降 |
manylinux_2_28 | 2.28 | AlmaLinux 8 以降(現在の推奨) |
cibuildwheel を使ったクロスプラットフォームビルド
複数 OS・アーキテクチャの wheel を CI で一括生成するには cibuildwheel が事実上の標準ツールだ。2025年6月リリースの v3.0 からデフォルトの manylinux イメージが manylinux_2_28 になっており、Python 3.11+ が必要になった。
# .github/workflows/build-wheels.yml
name: Build wheels
on:
push:
tags: ["v*"]
jobs:
build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v4
- name: Build wheels
uses: pypa/cibuildwheel@v3.0.0
env:
CIBW_BUILD: "cp311-* cp312-* cp313-*"
CIBW_ARCHS_MACOS: "x86_64 arm64"
- uses: actions/upload-artifact@v4
with:
name: cibw-wheels-${{ matrix.os }}
path: ./wheelhouse/*.whl
生成された wheel は wheelhouse/ に集まり、その後 twine upload や gh release upload で配布できる。
ローカルキャッシュと高速インストール
pip は ~/.cache/pip/wheels/ に wheel をキャッシュする。同じ環境を繰り返し作るプロジェクト(Docker マルチステージビルドなど)では、このキャッシュをマウントするだけでインストール時間を大幅短縮できる。
# syntax=docker/dockerfile:1
FROM python:3.13-slim AS builder
RUN --mount=type=cache,target=/root/.cache/pip \
pip install --upgrade pip && \
pip wheel -r requirements.txt -w /wheels
FROM python:3.13-slim
COPY --from=builder /wheels /wheels
RUN pip install --no-index --find-links=/wheels -r requirements.txt
pip wheel -r requirements.txt でまず wheel だけ生成し、本番イメージでは --no-index --find-links でオフラインインストールする2ステージ構成が Docker ベストプラクティスだ。
業務での使いどころ
社内パッケージの配布:社内ライブラリを wheel として社内 PyPI(devpi、Nexus、AWS CodeArtifact)にホストすると、利用者は pip install だけで使える。ソースを公開せずにビルド成果物のみ配布できるのもメリット。
CI の高速化:pip install の大半の時間はビルドではなくネットワーク取得だが、重い C 拡張パッケージ(NumPy、Pandas、OpenCV など)は wheel キャッシュの有無で数十秒変わる。GitHub Actions の actions/cache で ~/.cache/pip をキャッシュするだけで体感できる。
オフライン環境へのデプロイ:インターネット非接続のサーバーに Python 環境を構築する際、事前に wheel を収集(pip wheel -r requirements.txt)してまとめて持ち込むのが定石。
ハマりやすいポイント
プラットフォームタグのミスマッチ
win_amd64 向け wheel を ARM Mac にインストールしようとしても弾かれる。pip install --platform オプションでターゲットプラットフォームを指定してダウンロードだけ行うことも可能。
# ARM Linux 向け wheel を x86 マシンでダウンロードする例
pip download numpy \
--platform manylinux_2_17_aarch64 \
--python-version 313 \
--only-binary :all: \
--dest ./wheels/
linux_x86_64 タグは PyPI にアップロード不可
ローカルビルドした wheel には linux_x86_64 タグが付く。これは manylinux 準拠ではないため PyPI へのアップロードが拒否される。auditwheel repair で修正するか、cibuildwheel を使ってビルドする。
pip install auditwheel
auditwheel repair dist/mypackage-1.0-cp313-cp313-linux_x86_64.whl
# => wheelhouse/mypackage-1.0-cp313-cp313-manylinux_2_17_x86_64.whl
wheel の再ビルドを忘れる
pip install -e .(editable install)を使っている場合、C 拡張を変更したら再ビルドが必要だ。pip install -e . --no-build-isolation や python setup.py build_ext --inplace を忘れると古いバイナリが使われ続ける。
まとめ
- wheel は ZIP ベースのビルド済み配布形式。ビルドステップ不要で高速インストール
- ファイル名の
{python}-{abi}-{platform}タグを読めば対応環境がわかる - Pure Python は
py3-none-any、C 拡張は manylinux + cibuildwheel で配布 - Docker ビルドでは2ステージ構成+キャッシュマウントが高速化の定石
- Linux バイナリ wheel は
auditwheel repairで manylinux タグに変換してから PyPI へアップロード