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-anyPure Python、Python 3 全般、全プラットフォーム
cp313-cp313-win_amd64CPython 3.13、Windows 64bit
cp312-cp312-manylinux_2_17_x86_64CPython 3.12、Linux x86_64(GLIBC 2.17+)
cp311-abi3-linux_x86_64stable 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"]

ビルドバックエンドは hatchlingflit-coresetuptools など選択肢があるが、新規プロジェクトでは 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対応ディストリビューション目安
manylinux12.5CentOS 5 以降(廃止済)
manylinux20102.12CentOS 6 以降(廃止済)
manylinux2014 / manylinux_2_172.17CentOS 7 以降
manylinux_2_282.28AlmaLinux 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 uploadgh 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-isolationpython 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 へアップロード