今天遇到的问题,当我用
pip install pymupdf
时报× Encountered error while generating package metadata
,但是python -m pip install --prefer-binary pymupdf
却报Successfully installed pymupdf-1.26.0
。
若 pip 报错显示在编译某个 C/C++ 源文件失败,通常不是 pip 本身的问题,而是缺系统依赖或没有 wheel。想快速判断“是不是 wheel 的问题”:试
pip install --prefer-binary pymupdf
,若成功就说明是 wheel vs source 的差别。
为什么 pip 有时装不下来而 --prefer-binary 可以?
总结:遇到的 pymupdf 情况:如果没有合适的 wheel,pip 会尝试从源代码编译(这需要系统编译工具和 MuPDF 的头文件/库),编译失败就装不上;--prefer-binary
会让 pip 尽可能选择一个已有的 wheel(哪怕是旧版本),从而成功。
先来学一下 Python Package Formats
你会在包索引( 如 PyPI) 上找到两种格式的文件: 源发行版 ,简称 sdists,以及 二进制发行版 ,通常称为轮子 。例如,pip 23.3.1 的 PyPI 页面允许下载两个文件,pip-23.3.1.tar.gz
和 pip-23.3.1-py3-none-any.whl
。前者是 sdist,后者是轮子。在 PyPI(或其他地方)上发布包时,应该始终上传一个 sdist 和一个或多个 wheel。
PyPI 上每个包可能提供多种分发格式:wheel(二进制) 和 sdist(源码)。wheel 可以直接安装;sdist 需要在本机执行编译步骤(如果包包含扩展模块)。如果你的平台/Python 版本没有对应的 wheel,pip 就会下载 sdist 并尝试 build。
pip install pymupdf
:若 PyPI 上没有与当前 Python/平台匹配的 wheel,pip 会尝试构建(失败常见原因:缺少编译器、python-dev 头文件、或缺少第三方 C 库/头文件)。有 wheel 时直接安装速度又快又稳。PyMuPDF 文档也明确“如果有 wheel 则会从 wheel 安装”。--prefer-binary
的作用是优先选择二进制包(即使那不是最新版本),从而避免回退到源代码编译导致的失败。若没有任何可用 wheel,则仍然会回退(或失败)。(pip 文档有 –prefer-binary 的说明) 。
什么是源代码发行版?
从概念上讲,源代码发行版是原始形式的源代码存档。具体来说,sdist 是一个 .tar.gz
存档,其中包含源代码和一个名为 PKG-INFO 的附加特殊文件,该文件保存项目元数据。此文件的存在有助于打包工具提高效率,因为不需要自己计算元数据。PKG-INFO 文件遵循核心元数据规范中指定的格式,不打算手动编写。
当标准 Python 包安装程序 pip 找不到要安装的轮子时,它将回退到下载源代码发行版,从中编译轮子并安装轮子。此外,sdist 经常被下游打包者(例如 Linux 发行版、macOS 上的 Conda、Homebrew 和 MacPorts 等)用作包源,出于各种原因,他们可能更喜欢它们,例如从 Git 存储库中提取。
什么是轮子?
从概念上讲,滚轮恰好包含安装包时需要复制的文件。
对于 扩展模块 ,用 C、C++ 和 Rust 等编译语言编写,需要编译成依赖于平台的机器代码。使用这些包,轮子不包含源代码(如 C 源文件),而是包含编译的可执行代码(如 Linux 上的 .so 文件或 Windows 上的 DLL)。
一个轮子,通常适用于所有平台和 Python 版本。Python 是一种解释型语言,不需要提前编译,因此轮子像 sdists 一样包含 .py 文件。
轮子的文件名(忽略一些很少使用的功能)如下所示: package_name-version-python_tag-abi_tag-platform_tag.whl
。此命名约定标识滚轮与哪些平台和 Python 版本兼容。例如,名称 pip-23.3.1-py3-none-any.whl
表示:
- (
py3
) 这个轮子可以安装在 Python 3 的任何实现上,无论是 CPython(使用最广泛的 Python 实现),还是像 PyPy 这样的替代实现; - (
none
)它不依赖于 Python 版本; - (
any
) 它不依赖于平台。
conda 和 pip 有什么区别?优先用谁啊?
pip:从 PyPI 下载 Python 包的“Python 包管理器/安装器”,优先取 wheel(二进制包),没有 wheel 则回退到 source(sdist)并在本机编译。
--prefer-binary
会让 pip 更偏好二进制 wheel,避免本地编译。conda:是跨语言的包/环境管理器,以分发已编译的二进制包为主(包括非 Python 的系统库),从 conda 仓库或 channel(例如 conda-forge)取包,通常能避免本机编译 C/C++ 依赖。
两者适合的场景(何时用哪个)
- 优先用 conda(如果你在用 conda 环境):当包有复杂的 C/C++、外部库依赖(如科学栈、GDAL、ffmpeg、mupdf 等),能在 conda/conda-forge 上找到对应包时,conda 更稳,因为它 提供了已编译的二进制 并且 会处理底层库依赖。
- 用 pip 来补缺:如果某包在 conda 仓库里没有,或者 conda 的版本滞后,用 pip 在已激活的 conda 环境里安装通常可行(先用 conda 安装尽可能多的二进制依赖,再用 pip 安装纯 Python 包)。这也是官方常见建议的混合做法。
- 纯 Python 虚拟环境(venv/virtualenv)下:直接用 pip(PyPI)是最常见做法。对于需要编译的扩展,事先准备好编译器和 dev 库。
安装路径:pip / conda 分别装到哪里(如何查看)
pip(在当前 Python 环境中):会 装到该 Python 的 site-packages 中。常见位置(示例):
Linux/macOS(系统或自编译 Python):
/usr/local/lib/pythonX.Y/site-packages/
venv / conda env:
$VENV_OR_CONDA_PREFIX/lib/pythonX.Y/site-packages/
–user 模式:
~/.local/lib/pythonX.Y/site-packages/
(可通过python -m site --user-site
查看)。
查看某包路径:
pip show pymupdf
会输出 Location,或在 Python 里import pymupdf; print(pymupdf.__file__)
。conda:用
conda info --envs
可看环境位置。用 conda 时,先确认 conda-forge 是否有对应包并用该 channel 安装:
conda search -c conda-forge pymupdf conda install -c conda-forge pymupdf
在 conda env 中用 pip 安装,先激活 env,再用 pip,
conda activate myenv python -m pip install --upgrade pip setuptools wheel python -m pip install pymupdf # 或加 --prefer-binary