プラットフォームの互換性タグ¶
プラットフォーム相互互換性タグは、特定のプラットフォームと互換であるとビルドツールが配布物にマークを付けることができるようにし、インストーラが自身が動作しているシステムと互換であるのはどの配布物であるかを理解できるようにします。
概要¶
タグの書式は、 {python tag}-{abi tag}-{platform tag} です。
- python タグ
'py27' ・ 'cp33'
- abi タグ
'cp33dmu' ・ 'none'
- プラットフォームタグ
'linux_x86_64' ・ 'any'
例えば、py27-none-any というタグは、abi に対する要求なしに任意のプラットフォームで Python 2.7 (任意の Python 2.7 実装) との互換性を持つことを意味します。
wheel ビルド済みパッケージのフォーマットは、ファイル名の中にこのようなタグを {distribution}-{version}(-{build tag})?-{python tag}-{abitag}-{platform tag}.whl の形で包含しています。他のパッケージフォーマットにはそれぞれ独自の慣習があるかもしれません。
どのようなタグであれ、その中に潜在的に含まれる空白文字は _ で置換されるべきです。
Python タグ¶
Python タグは、配布物が必要とする実装やバージョンを示します。主要な実装には短縮系のコードがあって、当初は:
py: 一般的な Python (実装に特有な機能を要求しません)
cp: CPython
ip: IronPython
pp: PyPy
jy: Jython
他の Python 実装には sys.implementation.name を用いるべきです。
バージョンは py_version_nodot です。 CPython は no dot にせずに済ませますが、必要な場合には代わりにアンダースコア文字 _ が使用されます。 PyPy は、おそらく、ここに pp18 や pp19 といったそれ自身のバージョンを使います。
多くの純 Python 配布物では、バージョンは 2 や 3 や py2 ・ py3 といったメジャーバージョンだけにしておくことができます。
重要なことは、 py2 や py3 のような major-version-only タグは py20 や py30 の短縮形であるわけではないということです。そうではなくて、これらのタグは、パッケージ作成者がいくつものバージョンに互換性を持つ配布物を意図的にリリースしたのです。
単一ソースで Python 2/3 に互換性を持つ配布物は、合成タグ py2.py3 を用いることができます。 後述の タグの圧縮された組み合わせ を参照してください。
ABI タグ¶
ABI タグは、いずれかの拡張モジュールによってどのような Python ABI が要求されているのかを示します。実装依存の ABI 群については、実装 (の名前) は、たとえば cp33d がデバッグオプション付きの CPython 3.3 ABI のことを指すように、 Python タグと同様のやり方で短縮したものを使います。
CPython の安定版 ABI のことは、共有ライブラリの拡張子と同様に abi3 と書きます。
非常に不安定な ABI を持つ実装は、そのソースコードのリビジョンやコンパイラフラグその他の SHA-256 ハッシュ値の最初の6バイトを (BASE64にエンコードされた8文字として) 用いても構いませんが、おそらくはバイナリ配布物を配布することには大きな需要はないでしょう。それぞれの実装のコミュニティで ABI タグをどのように用いるのが最適かを決定すればよいでしょう。
プラットフォームタグ¶
重要
プラットフォームタグはオペレーティングシステムまたはプラットフォームのバージョン付けの表現に依存しており、下部構造となるプラットフォームがバージョン付けの方法を変更するにつれて、時間経過と共に変わるかもしれません。
基本的なプラットフォームタグ¶
最も単純な形式では、プラットフォームタグは、 sysconfig.get_platform() (の出力) のすべてのハイフン - と ピリオド . をアンダースコア _ で置き換えたものです。 Python 3.12 における distutils の削除があるまでは、これは distutils.util.get_platform() でした。例えば:
win32
linux_i386
linux_x86_64
manylinux¶
上記のような単純なスキームでは、Linux プラットフォーム向けに公開するための wheel ファイルの配布物用としては不十分で、それは、 Linux プラットフォーム群が巨大なエコシステムであって、プラットフォーム間に微妙な際が見られるためです。
代わりに、そのようなプラットフォーム向けには、 manylinux という標準が Linux プラットフォームの共通のサブセットを体現していて、 manylinux プラットフォームタグを付けて wheel をビルドすることで一般的な Linux のディストリビューションのほとんどで使えるようにすることができます。
現在の標準は、将来性が約束された manylinux_x_y 標準です。 manylinux_x_y_arch の形でタグを定義していて、 x と y には glibc のメジャーバージョンとマイナーバージョンがサポートされており (例えば manylinux_2_24_xxx であれば、 glibc 2.24+ を使うディストロならどれでも動作するはず)、 arch はアーキテクチャで、上記の "simple" 形式のシステム上での sysconfig.get_platform() の値に合致するものです。
この後に述べる古めのタグ群は、後方互換性のために今もサポートされています:
manylinux1は、x86_64とi686のアーキテクチャで libc 2.5 をサポートしています。manylinux2010は、x86_64とi686上で libc 2.12 をサポートしています。manylinux2014は、x86_64・i686・aarch64・armv7l・ppc64・ppc64le・s390x上で glibc 2.17 をサポートしています。
一般に、古めのバージョンの仕様向けにビルドされた配布物には前方互換性があります (というのは、 manylinux1 の配布物はより新しいシステムでも同様に動作するはずだということです) が、後方互換性はありません (manylinux2010 の配布物が 2010 年よりも前に存在していたプラットフォームで動作するとは想定されていないということです) 。
manylinux1 と manylinux2010 は既に end-of-life に達していて、提供されているビルド環境にはもはやセキュリティアップデートが提供されることはないであろうという警告されていることもあって、パッケージ保守者は最も互換性のある仕様をターゲットにするように努力するべきです。
適切なプロジェクトがサポートするさまざまな manylinux 標準の最低限のバージョンを次に掲げる表に示します:
ツール |
|
|
|
|
|---|---|---|---|---|
pip |
|
|
|
|
auditwheel |
|
|
|
|
musllinux¶
musllinux ファミリーに含まれるタグは manylinux に似ていますが、 glibc ではなくて musl libc を使う Linux プラットフォーム (最重要な例としては Alpine Linux) 向けのものです。文法としては musllinux_x_y_arch で、 musl x.y およびそれ以降で arch なるアーキテクチャをサポートします。
musl のバージョンの値は、 Python インタープリタが現在その上で走行している musl libc 共有ライブラリを実行し、その出力を字句解析することで得られます:
import re
import subprocess
def get_musl_major_minor(so: str) -> tuple[int, int] | None:
"""Detect musl runtime version.
Returns a two-tuple ``(major, minor)`` that indicates musl
library's version, or ``None`` if the given libc .so does not
output expected information.
The libc library should output something like this to stderr::
musl libc (x86_64)
Version 1.2.2
Dynamic Program Loader
"""
proc = subprocess.run([so], stderr=subprocess.PIPE, text=True)
lines = (line.strip() for line in proc.stderr.splitlines())
lines = [line for line in lines if line]
if len(lines) < 2 or lines[0][:4] != "musl":
return None
match = re.match(r"Version (\d+)\.(\d+)", lines[1])
if match:
return (int(match.group(1)), int(match.group(2)))
return None
Python インタープリタがその上で走行している musl ライブラリの場所を見つけるためには、現在、二つの可能なやり方があり、ひとつはシステムの ldd コマンドによるもの、もうひとつは 実行ファイルの ELF ヘッダから PT_INTERP セクションの値をパースする方法です。
macOS¶
macOSでは、 macosx ファミリーのタグを使います (末尾の x は、 Apple の公式の macOS 命名規則における歴史的な遺物です) 。互換性タグの文法は macosx_x_y_arch で、その wheel が、 macOS x.y およびそれ以降で、アーキテクチャが arch のものと互換性があることを示します。
macOS 10 向けには、タグは macosx_10_y_arch で、 y は macOS のリリースのマイナーバージョン番号に対応します。macOS 11 およびそれ以降のものについては、タグは macosx_x_0_arch で、 x は macOS リリースのメジャーバージョン番号に対応します。公開済みの macOS メジャーバージョンに従って、 x の値は 10 <= x <=15 か >=26 とその macOS リリースの年に対応するもののいずれかです。例えば、 macosx_11_0_arm64 は、 macOS 11 またはそれ以降のものとの互換性を示します。
macOS バイナリは単一のアーキテクチャ向けにコンパイルすることが可能で、あるいは、同じバイナリの中で複数のアーキテクチャのサポートを含めることも可能です (時に "fat" バイナリと呼ばれます) 。単一アーキテクチャ向けのサポートを示すためには、 arch の値は、そのシステム上での platform.machine() の値と一致していなければなりません。複数のアーキテクチャへのサポートを示すためには、 arch タグは、サポートされているアーキテクチャを記述する次のリストから採られた識別子であるべきです。
|
サポートされているアーキテクチャ |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
サポートされている macOS のバージョンで最小 (最古) のものは、また、アーキテクチャによって制約されるかもしれません。例えば、 macOS 11 (Big Sur) は arm64 をサポートした最初のリリースでした。このような追加的な制約は、複数のアーキテクチャをサポートするバイナリをビルドする時に、 macOS のコンパイルツールチェーンによって透過的に強制されます。
Android¶
Android は、 android_apilevel_abi のスキームを使っていて、当該 Android API レベルまたはそれ以降の当該 ABI との互換性を示しています。例えば、 android_27_arm64_v8a は、 API レベル 27 またはそれ以降で arm64_8va のデバイスをサポートすることを示しています。 Android は、物理的なデバイスとエミュレーションされたデバイスを区別しません。
API レベルは、正の整数であるべきです。これは、ユーザへの表示用の Android のバージョン番号と同じことでは ありません 。たとえば、 Android 12 (コードネーム "Snow Cone") は、使用されている Android のバージョン番号によって API 31 または 32 を使っています。 Android のリリース説明文書には、 Android の全てのバージョン番号とそれに対応する API レベル が含まれています。
4個の サポートされている ABIs があります。上記のルールに従って標準化すると、これらは:
armeabi_v7aarm64_v8ax86x86_64
現行のデバイスは、事実上すべてが ARM アーキテクチャのうちの一つを使っています。 x86 と x86_64 はエミュレータ内で使用するようにサポートされています。 x86 は、 2020 年以降は開発環境としてサポートされておらず、その時以来、新しいエミュレータイメージがリリースされていません。
iOS¶
iOS は ios_x_y_arch_sdk というスキーマを使っていて、 iOS x.y またはそれ以降で、 arch アーキテクチャのものであり、 sdk なる SDK を採用しているものとの互換性を示しています。
x と y の値は、それぞれ iOS リリースのメジャーとマイナーのバージョン番号に対応します。これらはどちらも正の整数でなければなりません。 Apple の公式のバージョン番号付与ではメジャーバージョンにだけ言及されるとはいえ、バージョン番号には常にメジャー および マイナーのバージョンを含みます。たとえば、 ios_13_0_arm64_iphonesimulator は iOS 13 およびそれ以降との互換性を示しています。
arch の値は、システム上の platform.machine() の値と一致していなければなりません。
sdk の値は、 (物理デバイス向けの) iphoneos または (シミュレータ向けの) iphonesimulator のいずれかでなければなりません。これらの SDK は、同一の API 表面を持っていますが、同じアーキテクチャの CPU 上で動作している時でさえ、バイナリレベルでは互換性がありません。 arm64 シミュレータ用にコンパイルされたソースコードは、 arm64 デバイスの上では動作しないでしょう。
arch_sdk の組み合わせは、 "マルチアーキテクチャ (マルチアーク) <multiarch>" と呼ばれます。3個の可能なマルチアークの値があります:
arm64_iphoneos、物理的な iPhone/iPad デバイス用のもの。これには、 2015 年頃以降に製造されたすべての iOS デバイスが含まれます;arm64_iphonesimulator、 Apple シリコン上の macOS ハードウェア上で動作するシミュレータ用のもの; そしてx86_64_iphonesimulator、 x86_64 ハードウェア上で動作するシミュレータ用のもの。
使い方¶
タグ類は、 (もしダウンロードが必要なら) 選択可能なビルド済配布物のリストの中からどれをダウンロードするのかをインストーラが決定するために使われます。インストーラは、自身がサポートする (pyver, abi, arch) タプルのリストを維持管理しています。ビルド済配布物のタグがリストに含まれて (in ) いれば、それをインストールすることができます。
古い Python リリース向けに発行された純 Python のバージョンにフォールバックするよりも前に、利用できる中で最も機能を網羅したビルド済配布物 (インストールする先の環境に最も適したもの) をインストーラがデフォルトで選択することが推奨されています。インストーラは、また、受け入れ可能な互換性タグのリストを設定変更したり順序を入れ替えたりする方法を持つことが推奨されています; 例えば、ユーザは、純 Python であると広報しているビルド済みパッケージだけをダウンロードするために、 *-none-any タグだけを受容しても構いません。
互換性はあるがもはや古くなってしまったビルド済みのものを使う選択肢よりもより好ましいという点で、インストーラに望まれるもうひとつの機能は "可能ならソースコードから再コンパイルする" でしょう。
この事例集は、インストーラを linux_x86_64 システム上の CPython 3.3 のもとで走らせるためのものです。最も好ましいもの (最新版の Python 向けにビルドされたコンパイル済みの拡張モジュールが付属している配布物) から、最も好ましくはないもの (古いバージョンの Python でビルドされた純 Python の配布物) へ、という順序で並んでいます:
cp33-cp33m-linux_x86_64
cp33-abi3-linux_x86_64
cp3-abi3-linux_x86_64
cp33-none-linux_x86_64*
cp3-none-linux_x86_64*
py33-none-linux_x86_64*
py3-none-linux_x86_64*
cp33-none-any
cp3-none-any
py33-none-any
py3-none-any
py32-none-any
py31-none-any
py30-none-any
ビルド済み配布物は、サブプロセスとして起動されるネーティブの実行可能ファイルを含んでいるなどのようなC 言語拡張以外の理由によって、特定のプラットフォーム向けであっても構いません。
時々、あるパッケージの特定のバージョンとして複数のビルド済み配布物が存在することがあるでしょう。例えば、パッケージ製作者が、 cp33-abi3-linux_x86_64 というタグを付けて追加的な C 言語拡張を含むパッケージをリリースし、そのようなものを含まない同じ配布物に py3-none-any というタグを付けてリリースするような場合です。(このような場合でも) サポートされるタグのリストで先に出現する方を優先するという理由によって C 言語拡張付きのパッケージがそうでないパッケージよりも選好されてインストールされるという形で、インデックスによってどちらかに決めることができます。
圧縮されたタグのセット¶
bdists のコンパクトなファイル名で、互換性のあるタグトリプルが複数ある場合にもきちんと動作するものを許容するためには、代わりにファイル名の中のそれぞれのタグが '.' で分割可能でありソート可能であるような一連のタグになっていることが可能です。例えば、 pip は純 Python のパッケージで、同一のソースコードで Python 2 でも 3 でも動作するように書かれていますが、これは py2.py3-none-any というタグを付けた bdist として配布することができるでしょう。単純なタグの完全なリストは:
for x in pytag.split('.'):
for y in abitag.split('.'):
for z in platformtag.split('.'):
yield '-'.join((x, y, z))
このスキームを実装する bdist フォーマットは、拡張されたタグ群を bdist に特有のメタデータの中に含んでいるべきです。この圧縮スキームは、サポートされていないタグや例えば "cp33-cp31u-win64" のようにいかなる Python 実装においてもサポートされていない "不可能な" タグを大量に生成すると思われるので、控えめに使うようにしてください。
FAQ¶
- デフォルトではどんなタグが使われますか?
ツール類は、
cp33-cp33m-win32のようなアーキテクチャへの依存を示すタグやpy33-none-anyのような純 Python タグの中で最も好ましいものをデフォルトで採用するべきです。パッケージ製作者がデフォルトをオーバーライドしていたとすれば、それは彼らが異なる Python 間での互換性を提供しようという意図があったことを示しています。- 自分の配布物が最新版の Python と相容れない機能を使っているとしたら、どんなタグを使いますか?
互換性タグは、インストーラがある配布物の 単一のバージョン の 最も互換性がある ビルドを選択する際に助けとなります。例えば、 (Python 3.4 に特有の機能を使っている)
beaglevote-1.2.0``には Python 3.3 と互換性を持つビルドがひとつもないという場合でも、 ``py34-none-anyタグの代わりにpy3-none-anyタグを使っても構いません。 Python 3.3 のユーザが互換性のあるビルドを得るためには、新しい機能を使う前のリリースであるbeaglevote-1.1.0用の要求 (requirement) などを他の指定子を組み合わせなければなりません。- Python のバージョン番号に
.がないのはなぜですか? CPython は、数字3個のメジャーリリースなしで 20 年以上にわたって存続してきました。これはしばらくの間は続くに違いありません。 - や . が周辺のファイル名を区切る役割を果たしているので、他の実装では _ を区切り子として使っても構いません。
- ハイフンやその他の英数字以外の文字をアンダースコアに正規化するのはなぜですか?
ファイル名の部分部分を区分けする
.文字や-文字との干渉を避けるために、かつ、 (クォートすることなく URL パス内で使用可能であることを含む) 数多あるファイルシステムのファイル名に対する制限事項との間のより良い互換性のために。- 何故、
.や-の代わりに特殊な文字 <X> を使わないのですか? それは、その文字が不便であるかコンテクストによっては潜在的に混乱を招きやすい (例えば
+は URL 内ではクォートしなければなりませんし、~は POSIX でユーザのホームディレクトリを示すために使われます) から、あるいは、 PEP 427 で定義された wheel フォーマットを参照して作成された既存の参照実装を変更すること (例えば、圧縮タグで部分部分を分割するのに.ではなく,を使うようにすること) を正当化するに足りるだけのアドバンテージがないから、のいずれかです。- 誰が実装に関する短縮形のレジストリの維持管理をしているのですか?
python-dev メーリングリストで要求することで、新しい2文字省略形の割り当てを受けることができるでしょう。経験上は、その時点で最も卓越した4個の実装のために省略形が予約されています。
- 互換性タグは METADATA に含まれるのか、あるいは PKG-INFO か?
否。互換性タグはビルド済み配布物のメタデータの一部です。METADATA / PKG-INFO は、その配布物の単一のビルドではなく配布物の全体にとって正当なものであるべきです。
- どうして私のお気に入りの Python 実装について言及しなかったの?
省略形タグは、コンパイル済みの Python コードを公開のインデックスでシェアすることを促進します。あなたの Python 実装においてもこの仕様を使うことができますが、しかしもっと長いタグになってしまうことでしょう。すべての "純 Python" なビルド済み配布物が単に
pyを使うだけであることを思い出してください。- どうして参照実装における ABI タグ (第2のタグ) は時々 "none" なのですか?
Python 2 では SOABI (より新しい版の Python 3 から来た概念) を作成する簡単な方法がないので、本稿執筆時点の参照実装は "none" なのです。理想的には、それはもっと新しい版の Python に相似の "py27(d|m|u)" を検出するようになるでしょうが、それまでの間は "知られていない" ことを示すのに "none" とすることが必要十分な方法なのです。
歴史¶
2013年2月: PEP 425 を通じてこの仕様の元々のバージョンが承認されました。
2016年1月: PEP 513 を通じて
manylinux1タグが承認されました。2018年4月: PEP 571 を通じて
manylinux2010タグが承認されました。2019年7月: PEP 599 を通じて
manylinux2014タグが承認されました。2019年11月: PEP 600 を通じて多年性の
manylinux_x_yタグが承認されました。2021年4月: PEP 656 を通じて
musllinux_x_yタグが承認されました。2023年12月: PEP 730 を通じて iOS 用のタグが承認されました。
2024年3月: PEP 738 を通じて Android 用のタグが承認されました。