真实对同一份pyproject.toml打出wheel和sdist两种产物,用unzip/tar直接拆开看里面装的到底是什么。
代码 pyproject.toml[build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [project] name = "pkga" version = "1.0.0" dependencies = ["libc<2.0"] python3 -m build --wheel --outdir wheelhouse pkga python3 -m build --sdist --outdir wheelhouse pkga file wheelhouse/pkga-1.0.0-py3-none-any.whl
file pkga-1.0.0-py3-none-any.whl → Zip archive data, at least v2.0 to extract ← 真实的文件类型判定,跟.zip完全一样 unzip -l pkga-1.0.0-py3-none-any.whl pkga/__init__.py pkga-1.0.0.dist-info/METADATA pkga-1.0.0.dist-info/WHEEL pkga-1.0.0.dist-info/top_level.txt pkga-1.0.0.dist-info/RECORD
这是本文认为wheel格式最容易被低估的真实事实:.whl后缀完全是约定,文件本身file命令识别出来的类型跟普通.zip没有任何区别——pip install some.whl真实做的核心动作,就是把这个zip解压到目标环境的site-packages目录,再根据RECORD里记录的文件清单确认解压结果完整。这跟本系列上一篇讲的《pip 依赖解析》衔接得上——resolver算出该装哪个版本之后,"装"这个动作本身在wheel格式下真实只是解压加校验,不需要重新编译或执行任意代码,这正是wheel比老式sdist(需要在安装现场跑一遍setup.py)快得多、也更可预测的原因。
unzip -p pkga-1.0.0-py3-none-any.whl pkga-1.0.0.dist-info/METADATA → Metadata-Version: 2.4 Name: pkga Version: 1.0.0 Requires-Dist: libc<2.0 ← 真实是pyproject.toml里dependencies字段翻译过来的 unzip -p pkga-1.0.0-py3-none-any.whl pkga-1.0.0.dist-info/RECORD → pkga/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 pkga-1.0.0.dist-info/METADATA,sha256=uu1BhI6rx9v9B9k5osYd7kDfTJpdB2mVvYiSbunEYZM,72 pkga-1.0.0.dist-info/WHEEL,sha256=...,91 pkga-1.0.0.dist-info/top_level.txt,sha256=...,5 pkga-1.0.0.dist-info/RECORD,, ← 真实这一行没有哈希,只有两个逗号
python3 -m build --sdist --outdir wheelhouse pkga tar tzf pkga-1.0.0.tar.gz → pkga-1.0.0/PKG-INFO pkga-1.0.0/pkga/__init__.py pkga-1.0.0/pkga.egg-info/... pkga-1.0.0/pyproject.toml ← 真实原样带上了完整的pyproject.toml pkga-1.0.0/setup.cfg ← 真实多出来的文件,我写的源码里根本没有这个文件
真实对比wheel和sdist的内容,能看出两者定位完全不同:wheel真实只装"最终产物"(已经处理好、可以直接放进site-packages的文件),不含pyproject.toml本身;sdist真实带的是完整的源码分发包,连构建配置都原样保留,pip install some.tar.gz拿到的是这份源码,还要在安装现场真的跑一次构建才能变成能用的模块。这份多出来的setup.cfg是setuptools构建后端真实自动生成的兼容文件(用于兼容一些只认老式setup.py/setup.cfg约定的工具链),不是我在源码里手写的——这提醒本文一件事:即使全程只写了pyproject.toml,构建工具背后真实可能会自己补出额外的元数据文件,打包产物不完全等于源码目录的原样打包。
每一步都是本文上面用真实构建的wheel/sdist跑出来的原始结果。
python -m build(setuptools后端)unzip / tar 直接拆开生成的wheel和sdist文件