跳转至

构建失败故障排除

当没有兼容的 wheel(预构建的软件包发行版)时,uv 需要构建软件包。构建软件包可能因多种原因失败,其中一些原因可能与 uv 本身无关。

识别构建失败

尝试在不受支持的新版 Python 上安装旧版本的 numpy 时,可能会出现构建失败示例:

$ uv pip install -p 3.13 'numpy<1.20'
在 62 毫秒内解析了 1 个软件包
  × 未能构建 `numpy==1.19.5`
  ├─▶ 构建后端返回错误
  ╰─▶ 调用 `setuptools.build_meta:__legacy__.build_wheel()` 失败(退出状态:1)

      [stderr]
      追溯(最近一次调用最后):
        文件 "<string>",第 8 行,在 <module> 中
          from setuptools.build_meta import __legacy__ as backend
        文件 "/home/konsti/.cache/uv/builds-v0/.tmpi4bgKb/lib/python3.13/site-packages/setuptools/__init__.py",第 9 行,在 <module> 中
          import distutils.core
      ModuleNotFoundError: 没有名为 'distutils' 的模块

      提示:`distutils` 在 Python 3.12 中已从标准库中移除。考虑添加约束条件(如 `numpy >1.19.5`),以避免构建依赖 `distutils` 的 `numpy` 版本。
请注意,错误消息以 “构建后端返回错误” 开头。

构建失败信息包括用于构建的构建后端的 [stderr](如果有,还有 [stdout])。错误日志并非来自 uv 本身。

╰─▶ 之后的消息是 uv 提供的提示,用于帮助解决常见的构建失败问题。并非所有构建失败都有提示。

确认构建失败是否特定于 uv

构建失败通常与您的系统和构建后端有关。特定于 uv 的构建失败情况很少见。您可以尝试使用 pip 重现该问题,以确认构建失败与 uv 无关:

$ uv venv -p 3.13 --seed
$ source .venv/bin/activate
$ pip install --use-pep517 --no-cache --force-reinstall 'numpy==1.19.5'
Collecting numpy==1.19.5
  Using cached numpy-1.19.5.zip (7.3 MB)
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
ERROR: Exception:
Traceback (most recent call last):
  ...
  File "/Users/example/.cache/uv/archive-v0/3783IbOdglemN3ieOULx2/lib/python3.13/site-packages/pip/_vendor/pyproject_hooks/_impl.py", line 321, in _call_hook
    raise BackendUnavailable(data.get('traceback', ''))
pip._vendor.pyproject_hooks._impl.BackendUnavailable: Traceback (most recent call last):
  File "/Users/example/.cache/uv/archive-v0/3783IbOdglemN3ieOULx2/lib/python3.13/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 77, in _build_backend
    obj = import_module(mod_path)
  File "/Users/example/.local/share/uv/python/cpython-3.13.0-macos-aarch64-none/lib/python3.13/importlib/__init__.py", line 88, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1310, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 1022, in exec_module
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "/private/var/folders/6p/k5sd5z7j31b31pq4lhn0l8d80000gn/T/pip-build-env-vdpjme7d/overlay/lib/python3.13/site-packages/setuptools/__init__.py", line 9, in <module>
    import distutils.core
ModuleNotFoundError: No module named 'distutils'

Important

pip install 调用中应包含 --use-pep517 标志,以确保相同的构建隔离行为。uv 默认始终使用构建隔离

我们还建议在重现失败时包含 --force-reinstall--no-cache 选项。

由于此构建失败在 pip 中也会出现,因此不太可能是 uv 的 bug。

如果使用其他安装程序也能重现构建失败,您应该向上游(在此示例中为 numpysetuptools)进行调查,首先找到避免构建该软件包的方法,或者对您的系统进行必要调整以使构建成功。

为什么 uv 要构建软件包?

在生成跨平台锁定文件时,uv 需要确定所有软件包的依赖项,即使是那些仅安装在其他平台上的依赖项。uv 会在解析过程中尽量避免构建软件包。如果存在该版本的 wheel 文件,它会使用该文件,然后尝试在源发行版中查找静态元数据(主要是包含静态 project.versionproject.dependenciesproject.optional-dependenciespyproject.toml 文件,或 METADATA v2.2+)。只有在所有这些尝试都失败时,它才会构建软件包。

在安装时,uv 需要为每个软件包准备适用于当前平台的 wheel 文件。如果索引中不存在匹配的 wheel 文件,uv 会尝试构建源发行版。

你可以在 “下载文件” 下查看 PyPI 项目存在哪些 wheel 文件,例如 https://pypi.org/project/numpy/2.1.1.md#files。文件名中包含 ...-py3-none-any.whl 的 wheel 文件可在任何地方使用,其他 wheel 文件的文件名中则包含操作系统和平台信息。在链接的 numpy 示例中,你可以看到针对 MacOS、Linux 和 Windows 上的 Python 3.10 到 3.13 有预构建的发行版。

常见的构建失败情况

以下示例展示了常见的构建失败情况以及如何解决它们。

找不到命令

如果构建错误提示缺少某个命令,例如 gcc

× 未能构建 `pysha3==1.0.2`
├─▶ 构建后端返回错误
╰─▶ 调用 `setuptools.build_meta:__legacy__.build_wheel` 失败(退出状态码:1)

    [标准输出]
    运行 bdist_wheel
    运行 build
    运行 build_py
    创建 build/lib.linux-x86_64-cpython-310
    将 sha3.py 复制到 build/lib.linux-x86_64-cpython-310
    运行 build_ext
    构建 '_pysha3' 扩展
    创建 build/temp.linux-x86_64-cpython-310/Modules/_sha3
    gcc -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -DPY_WITH_KECCAK=1 -I/root/.cache/uv/builds-v0/.tmp8V4iEk/include -I/usr/local/include/python3.10 -c
    Modules/_sha3/sha3module.c -o build/temp.linux-x86_64-cpython-310/Modules/_sha3/sha3module.o

    [标准错误输出]
    错误:命令 'gcc' 失败:没有那个文件或目录

那么,你需要使用系统包管理器安装该命令,例如,要解决上述错误:

$ apt install gcc

提示

使用 uv 管理的 Python 版本时,通常需要安装 clang 而非 gcc

许多 Linux 发行版提供了包含所有常见构建依赖项的软件包。你可以通过安装该软件包来满足大多数构建需求,例如,对于 Debian 或 Ubuntu:

$ apt install build-essential

缺少头文件或库

如果构建错误提示缺少头文件或库,例如某个 .h 文件,那么你需要使用系统包管理器来安装它。

例如,安装 pygraphviz 需要先安装 Graphviz:

× 未能构建 `pygraphviz==1.14`
├─▶ 构建后端返回错误
╰─▶ 调用 `setuptools.build_meta.build_wheel` 失败(退出状态码:1)

  [标准输出]
  运行 bdist_wheel
  运行 build
  运行 build_py
  ...
  gcc -fno-strict-overflow -Wsign-compare -DNDEBUG -g -O3 -Wall -fPIC -DSWIG_PYTHON_STRICT_BYTE_CHAR -I/root/.cache/uv/builds-v0/.tmpgLYPe0/include -I/usr/local/include/python3.12 -c pygraphviz/graphviz_wrap.c -o
  build/temp.linux-x86_64-cpython-312/pygraphviz/graphviz_wrap.o

  [标准错误输出]
  ...
  pygraphviz/graphviz_wrap.c:9: 警告:“SWIG_PYTHON_STRICT_BYTE_CHAR”重定义
      9 | #define SWIG_PYTHON_STRICT_BYTE_CHAR
        |
  <命令行>: 注意:这是上一次定义的位置
  pygraphviz/graphviz_wrap.c:3023:10: 致命错误:graphviz/cgraph.h:没有那个文件或目录
    3023 | #include "graphviz/cgraph.h"
        |          ^~~~~~~~~~~~~~~~~~~
  编译终止。
  错误:命令“/usr/bin/gcc”以退出码 1 失败

  提示:此错误可能表明你需要为 `pygraphviz@1.14` 安装提供“graphviz/cgraph.h”的库

要在 Debian 上解决此错误,你需要安装 libgraphviz-dev 包:

$ apt install libgraphviz-dev

请注意,仅安装 graphviz 包是不够的,还需要安装开发头文件。

提示

要解决 Python.h 缺失的错误,请安装 python3-dev

模块缺失或无法导入

如果构建错误提示导入失败,可以考虑禁用构建隔离

例如,有些软件包在未将 pip 声明为构建依赖项的情况下,就假定 pip 可用:

  × 未能构建 `chumpy==0.70`
  ├─▶ 构建后端返回错误
  ╰─▶ 调用 `setuptools.build_meta:__legacy__.build_wheel` 失败(退出状态码:1)

    [stderr]
    追溯(最近一次调用):
      文件 “<string>”,第 9 行,在 <module> 中
    ModuleNotFoundError: 没有名为 'pip' 的模块

    在处理上述异常期间,发生了另一个异常:

    追溯(最近一次调用):
      文件 “<string>”,第 14 行,在 <module> 中
      文件 “/root/.cache/uv/builds-v0/.tmpvvHaxI/lib/python3.12/site-packages/setuptools/build_meta.py”,第 334 行,在 get_requires_for_build_wheel 中
        return self._get_build_requires(config_settings, requirements=[])
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      文件 “/root/.cache/uv/builds-v0/.tmpvvHaxI/lib/python3.12/site-packages/setuptools/build_meta.py”,第 304 行,在 _get_build_requires 中
        self.run_setup()
      文件 “/root/.cache/uv/builds-v0/.tmpvvHaxI/lib/python3.12/site-packages/setuptools/build_meta.py”,第 522 行,在 run_setup 中
        super().run_setup(setup_script=setup_script)
      文件 “/root/.cache/uv/builds-v0/.tmpvvHaxI/lib/python3.12/site-packages/setuptools/build_meta.py”,第 320 行,在 run_setup 中
        exec(code, locals())
      文件 “<string>”,第 11 行,在 <module> 中
    ModuleNotFoundError: 没有名为 'pip' 的模块

要解决此错误,先安装构建依赖项,然后针对该软件包禁用构建隔离:

$ uv pip install pip setuptools
$ uv pip install chumpy --no-build-isolation-package chumpy

请注意,你需要安装缺失的软件包(例如 pip)以及该软件包的所有其他构建依赖项(例如 setuptools)。

构建的是旧版本的软件包

如果在解析过程中某个软件包构建失败,且构建失败的版本比你想要使用的版本旧,可以尝试添加一个带有下限的约束条件(例如 numpy>=1.17)。有时,由于算法限制,uv 解析器会尝试使用不合理的旧软件包来寻找合适的版本,而使用下限可以避免这种情况。

例如,在 Python 3.10 上解析以下依赖项时,uv 会尝试构建旧版本的 apache-beam

requirements.txt
dill<0.3.9,>=0.2.2
apache-beam<=2.49.0
× Failed to build `apache-beam==2.0.0`
├─▶ The build backend returned an error
╰─▶ Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)

    [stderr]
    ...

添加下限约束,例如 apache-beam<=2.49.0,>2.30.0,可以解决此构建失败问题,因为 uv 将避免使用旧版本的 apache-beam

也可以使用 constraints.txt 文件或constraint-dependencies 设置为间接依赖项定义约束条件。

使用了构建依赖的旧版本

如果某个软件包因 uv 选择了不兼容或过时的构建时依赖版本而无法构建,你可以专门对构建依赖实施约束。可以使用 build-constraint-dependencies 设置(或类似的 build-constraints.txt 文件)来确保 uv 选择给定构建需求的合适版本。

例如,#5551 中描述的问题可以通过指定一个排除 setuptools 版本 72.0.0 的构建约束来解决:

pyproject.toml
[tool.uv]

# 防止将 setuptools 72.0.0 版本用作构建依赖。
build-constraint-dependencies = ["setuptools!=72.0.0"]

因此,构建约束将确保在构建过程中任何需要 setuptools 的软件包都不会使用有问题的版本,从而避免因不兼容的构建依赖导致的构建失败。

软件包仅用于未使用的平台

如果由于从你无需支持的平台构建软件包而导致锁定失败,可以考虑将解析范围限制在你支持的平台上。

软件包并非支持所有 Python 版本

如果你支持大范围的 Python 版本,可以考虑使用标记,对较旧的 Python 版本使用较旧的版本,对较新的 Python 版本使用较新的版本。例如,numpy 一次仅支持四个 Python 次版本,因此,为了支持更广泛的 Python 版本,例如 Python 3.8 到 3.13,需要拆分 numpy 需求:

numpy>=1.23; python_version >= "3.10"
numpy<1.23; python_version < "3.10"

包仅在特定平台上可用

如果由于构建仅在其他平台上可用的包而导致锁定失败,你可以手动提供依赖元数据以跳过构建。uv 无法验证此信息,因此在使用此覆盖时指定正确的元数据非常重要。