Skip to content

빌드 실패 문제 해결

uv는 호환 가능한 휠(사전 빌드된 패키지 배포본)이 없을 때 패키지를 빌드해야 한다. 패키지 빌드는 다양한 이유로 실패할 수 있으며, 그 중 일부는 uv 자체와 무관한 문제일 수 있다.

빌드 실패 인지하기

새로운 버전의 Python에서 지원되지 않는 오래된 numpy 버전을 설치하려고 시도하면 빌드 실패 예제를 확인할 수 있다:

$ uv pip install -p 3.13 'numpy<1.20'
Resolved 1 package in 62ms
  × Failed to build `numpy==1.19.5`
  ├─▶ The build backend returned an error
  ╰─▶ Call to `setuptools.build_meta:__legacy__.build_wheel()` failed (exit status: 1)

      [stderr]
      Traceback (most recent call last):
        File "<string>", line 8, in <module>
          from setuptools.build_meta import __legacy__ as backend
        File "/home/konsti/.cache/uv/builds-v0/.tmpi4bgKb/lib/python3.13/site-packages/setuptools/__init__.py", line 9, in <module>
          import distutils.core
      ModuleNotFoundError: No module named 'distutils'

      hint: `distutils` was removed from the standard library in Python 3.12. Consider adding a constraint (like `numpy >1.19.5`) to avoid building a version of `numpy` that depends
      on `distutils`.

에러 메시지 앞에 "The build backend returned an error"라는 문구가 표시된다.

빌드 실패에는 빌드에 사용된 빌드 백엔드의 [stderr](그리고 [stdout]도 존재한다면)가 포함된다. 에러 로그는 uv 자체에서 발생한 것이 아니다.

╰─▶ 다음에 나오는 메시지는 uv가 제공하는 힌트로, 일반적인 빌드 실패를 해결하는 데 도움을 준다. 모든 빌드 실패에 힌트가 제공되는 것은 아니다.

빌드 실패가 uv와 관련된지 확인하기

빌드 실패는 대부분 시스템과 빌드 백엔드와 관련이 있다. 빌드 실패가 uv와 직접적으로 관련된 경우는 드물다. 빌드 실패가 uv와 무관한지 확인하려면 pip를 사용해 동일한 실패를 재현해볼 수 있다:

$ 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의 버그일 가능성이 낮다.

빌드 실패가 다른 설치 프로그램에서도 재현된다면, 상위 프로젝트(이 예제에서는 numpy 또는 setuptools)를 조사하거나, 패키지 빌드를 피할 방법을 찾거나, 빌드가 성공하도록 시스템을 조정해야 한다.

uv가 패키지를 빌드하는 이유

크로스 플랫폼 lockfile을 생성할 때, uv는 모든 패키지의 의존성을 파악해야 한다. 다른 플랫폼에만 설치된 패키지도 포함된다. uv는 의존성 해결 과정에서 패키지 빌드를 최대한 피하려고 한다. 해당 버전에 대한 wheel이 존재하면 이를 사용하고, 소스 배포판에서 정적 메타데이터(주로 project.version, project.dependencies, project.optional-dependencies가 포함된 pyproject.toml 또는 METADATA v2.2+)를 찾는다. 이 모든 방법이 실패할 때만 패키지를 빌드한다.

패키지를 설치할 때, uv는 현재 플랫폼에 맞는 wheel이 필요하다. 인덱스에 적합한 wheel이 없으면 uv는 소스 배포판을 빌드한다.

PyPI 프로젝트에서 사용 가능한 wheel은 "Download Files" 섹션에서 확인할 수 있다. 예를 들어, https://pypi.org/project/numpy/2.1.1.md#files를 보면 ...-py3-none-any.whl 파일명을 가진 wheel은 모든 환경에서 작동한다. 다른 wheel은 파일명에 운영체제와 플랫폼이 명시되어 있다. 링크된 numpy 예제에서는 Python 3.10부터 3.13까지 MacOS, Linux, Windows용으로 사전 빌드된 배포판이 있음을 확인할 수 있다.

일반적인 빌드 실패 사례

다음 예제들은 빌드 과정에서 자주 발생하는 문제와 해결 방법을 보여준다.

커맨드를 찾을 수 없음

빌드 오류가 gcc와 같은 누락된 커맨드를 언급한다면:

× `pysha3==1.0.2` 빌드 실패
├─▶ 빌드 백엔드에서 오류 반환
╰─▶ `setuptools.build_meta:__legacy__.build_wheel` 호출 실패 (종료 상태: 1)

    [stdout]
    running bdist_wheel
    running build
    running build_py
    creating build/lib.linux-x86_64-cpython-310
    copying sha3.py -> build/lib.linux-x86_64-cpython-310
    running build_ext
    building '_pysha3' extension
    creating 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

    [stderr]
    error: 'gcc' 커맨드 실패: 파일 또는 디렉터리가 없음

이 경우, 시스템 패키지 관리자를 사용해 해당 커맨드를 설치해야 한다. 예를 들어 위 오류를 해결하려면:

$ apt install gcc

Tip

uv가 관리하는 Python 버전을 사용할 때는 gcc 대신 clang이 필요한 경우가 많다.

많은 Linux 배포판은 일반적인 빌드 의존성을 모두 포함하는 패키지를 제공한다. 이를 설치하면 대부분의 빌드 요구 사항을 해결할 수 있다. 예를 들어 Debian이나 Ubuntu에서는:

$ apt install build-essential

헤더 또는 라이브러리가 누락된 경우

빌드 오류가 .h 파일과 같은 누락된 헤더나 라이브러리를 언급한다면, 시스템 패키지 매니저를 통해 해당 파일을 설치해야 한다.

예를 들어, pygraphviz를 설치하려면 Graphviz가 필요하다:

× `pygraphviz==1.14` 빌드 실패
├─▶ 빌드 백엔드에서 오류 반환
╰─▶ `setuptools.build_meta.build_wheel` 호출 실패 (종료 상태: 1)

  [stdout]
  running bdist_wheel
  running build
  running 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

  [stderr]
  ...
  pygraphviz/graphviz_wrap.c:9: warning: "SWIG_PYTHON_STRICT_BYTE_CHAR" 재정의
      9 | #define SWIG_PYTHON_STRICT_BYTE_CHAR
        |
  <command-line>: note: 이전 정의 위치
  pygraphviz/graphviz_wrap.c:3023:10: fatal error: graphviz/cgraph.h: 파일 또는 디렉토리가 없음
    3023 | #include "graphviz/cgraph.h"
        |          ^~~~~~~~~~~~~~~~~~~
  컴파일 종료.
  error: '/usr/bin/gcc' 명령이 종료 코드 1로 실패함

  hint: 이 오류는 `pygraphviz@1.14`에 필요한 "graphviz/cgraph.h"를 제공하는 라이브러리를 설치해야 함을 나타낼 수 있음

Debian에서 이 오류를 해결하려면 libgraphviz-dev 패키지를 설치한다:

$ apt install libgraphviz-dev

graphviz 패키지만 설치하는 것으로는 충분하지 않다. 개발 헤더도 함께 설치해야 한다.

Tip

Python.h가 누락된 오류를 해결하려면 python3-dev 패키지를 설치한다.

모듈이 누락되었거나 임포트할 수 없음

빌드 오류가 임포트 실패를 언급한다면, 빌드 격리 기능을 비활성화하는 것을 고려해 보세요.

예를 들어, 일부 패키지는 pip를 빌드 종속성으로 선언하지 않고도 사용 가능하다고 가정합니다:

  × `chumpy==0.70` 빌드 실패
  ├─▶ 빌드 백엔드가 오류를 반환함
  ╰─▶ `setuptools.build_meta:__legacy__.build_wheel` 호출 실패 (종료 상태: 1)

    [stderr]
    Traceback (most recent call last):
      File "<string>", line 9, in <module>
    ModuleNotFoundError: 'pip' 모듈을 찾을 수 없음

    위 예외를 처리하는 동안 다른 예외가 발생함:

    Traceback (most recent call last):
      File "<string>", line 14, in <module>
      File "/root/.cache/uv/builds-v0/.tmpvvHaxI/lib/python3.12/site-packages/setuptools/build_meta.py", line 334, in get_requires_for_build_wheel
        return self._get_build_requires(config_settings, requirements=[])
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/root/.cache/uv/builds-v0/.tmpvvHaxI/lib/python3.12/site-packages/setuptools/build_meta.py", line 304, in _get_build_requires
        self.run_setup()
      File "/root/.cache/uv/builds-v0/.tmpvvHaxI/lib/python3.12/site-packages/setuptools/build_meta.py", line 522, in run_setup
        super().run_setup(setup_script=setup_script)
      File "/root/.cache/uv/builds-v0/.tmpvvHaxI/lib/python3.12/site-packages/setuptools/build_meta.py", line 320, in run_setup
        exec(code, locals())
      File "<string>", line 11, in <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
× `apache-beam==2.0.0` 빌드 실패
├─▶ 빌드 백엔드에서 오류 반환
╰─▶ `setuptools.build_meta:__legacy__.build_wheel` 호출 실패 (종료 상태: 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 3.8부터 3.13까지 더 넓은 범위의 버전을 지원하려면 numpy 요구 사항을 다음과 같이 분리해야 한다:

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

패키지가 특정 플랫폼에서만 사용 가능한 경우

패키지가 다른 플랫폼에서만 사용 가능하여 빌드가 실패하는 경우, 의존성 메타데이터를 수동으로 제공하여 빌드를 건너뛸 수 있다. uv는 이 정보를 검증하지 않으므로, 이 방법을 사용할 때 정확한 메타데이터를 지정하는 것이 중요하다.