- 為什么 pip 有時裝不下來而 --prefer-binary 可以?
- 什么是源代碼發行版?
- 什么是輪子?
- conda 和 pip 有什么區別?優先用誰啊?
- 兩者適合的場景(何時用哪個)
- 安裝路徑:pip / conda 分別裝到哪里(如何查看)
今天遇到的問題,當我用
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
) 它不依賴于平臺。
More Info about wheel to see here.
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