本地电脑安装 gevent 21.1.2 失败原因分析

1,175 阅读6分钟

本地电脑安装指定的 pip 包失败,出错信息

Using pip 23.0.1 from /Users/xxx/venv/lib/python3.8/site-packages/pip (python 3.8)
  Link requires a different Python (3.8.18 not in: '>=3.9'): https://files.pythonhosted.org/packages/cf/5f/c7ed67457700ed2d2888b3e4f36dd7cfbe195aa28dd605980d30939c0878/gevent-24.10.1.tar.gz (from https://pypi.org/simple/gevent/) (requires-python:>=3.9)
  Link requires a different Python (3.8.18 not in: '>=3.9'): https://files.pythonhosted.org/packages/72/91/e870ada18283016ee8e87d182fa2a092fedbc3d08c361e10800347de21d3/gevent-24.10.2.tar.gz (from https://pypi.org/simple/gevent/) (requires-python:>=3.9)
  Link requires a different Python (3.8.18 not in: '>=3.9'): https://files.pythonhosted.org/packages/70/f0/be10ed5d7721ed2317d7feb59e167603217156c2a6d57f128523e24e673d/gevent-24.10.3.tar.gz (from https://pypi.org/simple/gevent/) (requires-python:>=3.9)
  Link requires a different Python (3.8.18 not in: '>=3.9'): https://files.pythonhosted.org/packages/ab/75/a53f1cb732420f5e5d79b2563fc3504d22115e7ecfe7966e5cf9b3582ae7/gevent-24.11.1.tar.gz (from https://pypi.org/simple/gevent/) (requires-python:>=3.9)
  Link requires a different Python (3.8.18 not in: '>=3.9'): https://files.pythonhosted.org/packages/ca/09/5ac96eece3f119d6d43694d81f26609aaeef00e5e306f0bc98afa7a57b98/gevent-25.4.1.tar.gz (from https://pypi.org/simple/gevent/) (requires-python:>=3.9)
  Link requires a different Python (3.8.18 not in: '>=3.9'): https://files.pythonhosted.org/packages/00/e5/a2d9c2d5bfb575973bca7733b23e7f8649f1079c18140a8680a551f3963e/gevent-25.4.2.tar.gz (from https://pypi.org/simple/gevent/) (requires-python:>=3.9)
Collecting gevent==21.1.2
  Using cached gevent-21.1.2.tar.gz (5.9 MB)
  Running command pip subprocess to install build dependencies
  Collecting setuptools>=40.8.0
    Downloading setuptools-75.3.2-py3-none-any.whl (1.3 MB)
       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.3/1.3 MB 3.2 MB/s eta 0:00:00
  Collecting wheel
    Downloading wheel-0.45.1-py3-none-any.whl (72 kB)
       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 72.5/72.5 kB 7.3 MB/s eta 0:00:00
  Collecting Cython>=3.0a6
    Downloading cython-3.1.0-cp38-cp38-macosx_11_0_arm64.whl (2.9 MB)
       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.9/2.9 MB 5.0 MB/s eta 0:00:00
  Collecting cffi>=1.12.3
    Downloading cffi-1.17.1.tar.gz (516 kB)
       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 516.6/516.6 kB 6.0 MB/s eta 0:00:00
    Installing build dependencies: started
    Installing build dependencies: finished with status 'done'
    Getting requirements to build wheel: started
    Getting requirements to build wheel: finished with status 'done'
    Preparing metadata (pyproject.toml): started
    Preparing metadata (pyproject.toml): finished with status 'done'
  Collecting greenlet<2.0,>=0.4.17
    Using cached greenlet-1.1.3.post0-cp38-cp38-macosx_14_0_arm64.whl
  Collecting pycparser
    Using cached pycparser-2.22-py3-none-any.whl (117 kB)
  Building wheels for collected packages: cffi
    Building wheel for cffi (pyproject.toml): started
    Building wheel for cffi (pyproject.toml): finished with status 'done'
    Created wheel for cffi: filename=cffi-1.17.1-cp38-cp38-macosx_14_0_arm64.whl size=179113 sha256=2dffcb9537885e262c3bd73a0305adb87cfe6d9f14604693edd4c769a12011dc
    Stored in directory: /Users/xxx/Library/Caches/pip/wheels/f8/73/f0/643f1772516a6bd314c8e57831b7d5204a45e9fe1b876b6b35
  Successfully built cffi
  Installing collected packages: wheel, setuptools, pycparser, greenlet, Cython, cffi
  Successfully installed Cython-3.1.0 cffi-1.17.1 greenlet-1.1.3.post0 pycparser-2.22 setuptools-75.3.2 wheel-0.45.1
  WARNING: There was an error checking the latest version of pip.
  Installing build dependencies ... done
  Running command Getting requirements to build wheel
  Compiling src/gevent/resolver/cares.pyx because it changed.
  [1/1] Cythonizing src/gevent/resolver/cares.pyx
  performance hint: src/gevent/libev/corecext.pyx:1325:0: Exception check on '_syserr_cb' will always require the GIL to be acquired.
  Possible solutions:
        1. Declare '_syserr_cb' as 'noexcept' if you control the definition and you're sure you don't want the function to raise exceptions.
        2. Use an 'int' return type on '_syserr_cb' to allow an error code to be returned.

  Error compiling Cython file:
  ------------------------------------------------------------
  ...
  cdef tuple integer_types

  if sys.version_info[0] >= 3:
      integer_types = int,
  else:
      integer_types = (int, long)
                            ^
  ------------------------------------------------------------

  src/gevent/libev/corecext.pyx:60:26: undeclared name not builtin: long
  Compiling src/gevent/libev/corecext.pyx because it changed.
  [1/1] Cythonizing src/gevent/libev/corecext.pyx
  Traceback (most recent call last):
    File "/Users/xxx/venv/lib/python3.8/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 353, in <module>
      main()
    File "/Users/xxx/venv/lib/python3.8/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 335, in main
      json_out['return_val'] = hook(**hook_input['kwargs'])
    File "/Users/xxx/venv/lib/python3.8/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 118, in get_requires_for_build_wheel
      return hook(config_settings)
    File "/private/var/folders/w0/0447kss56817yrbrmxcsw9fw0000gn/T/pip-build-env-wn5n6pwr/overlay/lib/python3.8/site-packages/setuptools/build_meta.py", line 333, in get_requires_for_build_wheel
      return self._get_build_requires(config_settings, requirements=[])
    File "/private/var/folders/w0/0447kss56817yrbrmxcsw9fw0000gn/T/pip-build-env-wn5n6pwr/overlay/lib/python3.8/site-packages/setuptools/build_meta.py", line 303, in _get_build_requires
      self.run_setup()
    File "/private/var/folders/w0/0447kss56817yrbrmxcsw9fw0000gn/T/pip-build-env-wn5n6pwr/overlay/lib/python3.8/site-packages/setuptools/build_meta.py", line 521, in run_setup
      super().run_setup(setup_script=setup_script)
    File "/private/var/folders/w0/0447kss56817yrbrmxcsw9fw0000gn/T/pip-build-env-wn5n6pwr/overlay/lib/python3.8/site-packages/setuptools/build_meta.py", line 319, in run_setup
      exec(code, locals())
    File "<string>", line 50, in <module>
    File "/private/var/folders/w0/0447kss56817yrbrmxcsw9fw0000gn/T/pip-install-vw2o83sa/gevent_10f2d16e5fd3463abc91a63309ec8db9/_setuputils.py", line 237, in cythonize1
      new_ext = cythonize(
    File "/private/var/folders/w0/0447kss56817yrbrmxcsw9fw0000gn/T/pip-build-env-wn5n6pwr/overlay/lib/python3.8/site-packages/Cython/Build/Dependencies.py", line 1145, in cythonize
      cythonize_one(*args)
    File "/private/var/folders/w0/0447kss56817yrbrmxcsw9fw0000gn/T/pip-build-env-wn5n6pwr/overlay/lib/python3.8/site-packages/Cython/Build/Dependencies.py", line 1289, in cythonize_one
      raise CompileError(None, pyx_file)
  Cython.Compiler.Errors.CompileError: src/gevent/libev/corecext.pyx
  error: subprocess-exited-with-error
  
  × Getting requirements to build wheel did not run successfully.
  │ exit code: 1
  ╰─> See above for output.
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
  full command: /Users/xxx/venv/bin/python3 /Users/xxx/venv/lib/python3.8/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py get_requires_for_build_wheel /var/folders/w0/0447kss56817yrbrmxcsw9fw0000gn/T/tmplcoho6uu
  cwd: /private/var/folders/w0/0447kss56817yrbrmxcsw9fw0000gn/T/pip-install-vw2o83sa/gevent_10f2d16e5fd3463abc91a63309ec8db9
  Getting requirements to build wheel ... error
error: subprocess-exited-with-error

× Getting requirements to build wheel did not run successfully.
│ exit code: 1
╰─> See above for output.

note: This error originates from a subprocess, and is likely not a problem with pip.
WARNING: There was an error checking the latest version of pip.

环境信息

先看看本地的环境信息,有助于定位问题。

# 查看 Python 版本
python --version

# 查看 pip 版本
pip --version

# 查看操作系统信息
uname -a 

安装过程解析

1. 版本筛选和兼容性检查

Using pip 23.0.1 from /Users/xxx/venv/lib/python3.8/site-packages/pip (python 3.8)
Link requires a different Python (3.8.18 not in: '>=3.9'): ...
  • pip 首先检查了可用的 gevent 版本,发现较新版本(24.x 和 25.x)都要求 Python 3.9+
  • 由于使用的是 Python 3.8.18,pip 自动跳过了这些不兼容的版本

2. 获取指定版本源码

Collecting gevent==21.1.2
  Using cached gevent-21.1.2.tar.gz (5.9 MB)
  • pip 找到并下载了指定的 gevent 21.1.2 源码包,需要在本地编译这个包

3. 安装构建依赖

Running command pip subprocess to install build dependencies
  • pip 创建了临时环境安装了编译 gevent 所需的所有依赖项:
    • setuptools 75.3.2
    • wheel 0.45.1
    • Cython 3.1.0(关键点
    • cffi 1.17.1
    • greenlet 1.1.3.post0
    • pycparser 2.22

4. 编译过程开始

Compiling src/gevent/resolver/cares.pyx because it changed.
[1/1] Cythonizing src/gevent/resolver/cares.pyx
  • 开始使用 Cython 编译 gevent 的 C 扩展
  • 首先编译了 cares.pyx 文件

5. 编译错误 - 不兼容的 Cython 语法

Error compiling Cython file:
...
if sys.version_info[0] >= 3:
    integer_types = int,
else:
    integer_types = (int, long)
                          ^
src/gevent/libev/corecext.pyx:60:26: undeclared name not builtin: long
  • 错误发生在 corecext.pyx 文件中
  • 问题:Python 3 中不存在 long 类型(在 Python 2 中存在),但代码仍然引用了它
  • Cython 3.1.0 不再支持这种语法,而 gevent 21.1.2 的代码是为旧版 Cython 写的

6. 构建过程失败

Cython.Compiler.Errors.CompileError: src/gevent/libev/corecext.pyx
error: subprocess-exited-with-error
  • 由于 Cython 编译失败,整个构建过程中止
  • pip 无法完成 gevent 的安装

7. 核心问题分析

  1. 版本不兼容:gevent 21.1.2 使用的是针对旧版 Cython 的语法,但安装过程自动选择了 Cython 3.1.0(最新版)

gevent 代码确认

下载源码

mkdir gevent_src && cd gevent_src

# 直接从PyPI下载源码包
wget https://files.pythonhosted.org/packages/source/g/gevent/gevent-21.1.2.tar.gz

# 解压缩
tar -xzf gevent-21.1.2.tar.gz

# 进入源码目录
cd gevent-21.1.2

查看 pyproject.toml

  • build-backend = "setuptools.build_meta:__legacy__":指定使用 setuptools __legacy__构建后端
  • requires:指定构建依赖项列表

依赖项分析

依赖项配置显示这是一个复杂的 C 扩展项目,需要:

  • setuptools >= 40.8.0wheel:基本构建工具
  • Cython >= 3.0a6:用于将 Python 代码转换为 C 代码以提高性能
  • cffi >= 1.12.3:C 外部函数接口
  • greenlet >= 0.4.17, < 2.0:协程库

构建过程

当使用 Python 构建工具(如 pip install . 或 python -m build)构建此项目时:

  • 读取配置:构建工具解析 pyproject.toml 文件
  • 安装构建依赖:安装 requires 列表中的所有包
  • 调用构建后端:使用 setuptools.build_meta:__legacy__ 进行构建
  • 该后端会执行 setup.py 脚本
  • 传统模式确保 setup.py 可以导入当前目录中的模块
  • Cython 处理:Cython 会将 .py 或 .pyx 文件转换为 C 代码
  • 编译扩展:C 代码被编译成扩展模块(.so 或 .pyd 文件)
  • 创建分发包:生成 wheel 和/或 源码分发包

其他:pip 的缓存

pip 缓存通常存储在以下位置:

  • 在 macOS/Linux 上:~/.cache/pip
  • 在 Windows 上:%LOCALAPPDATA%\pip\Cache

如何不使用缓存

如果想强制 pip 不使用缓存重新下载包,可以使用 --no-cache-dir 参数:

pip install gevent==21.1.2 --no-cache-dir

这个命令会忽略当前缓存的包,重新从 PyPI 或其他包源下载所需的包。

清除 pip 缓存

果你想完全清除 pip 的缓存,可以使用:

pip cache purge

或者较老版本的 pip:

pip cache remove gevent
# 或者清除所有缓存
pip cache remove *