返回

pip cryptography 报错 1120? 轻松修复 link.exe 失败

windows

搞定 pip install cryptography 报错:link.exe failed with exit status 1120

装 Python 包 cryptography 的时候,你可能兴冲冲地敲下 pip install cryptography,结果屏幕喷出一大堆红字,最后一句是扎眼的 error: command '...link.exe' failed with exit status 1120。别灰心,这问题虽然看起来吓人,但通常不是啥绝症。咱们来捋一捋,看看怎么干掉它。

遇到这个报错,说明 pip 在尝试编译 cryptography 包里的 C 语言扩展模块时,在最后“链接”那一步栽了跟头。link.exe 是 Visual Studio C++ 编译器工具链里负责把编译好的目标文件(.obj)和库文件(.lib)“粘”在一起,生成最终的可执行文件(.pyd,也就是 Python 能加载的 DLL)的工具。错误码 1120 赤裸裸地告诉你:“有几个零件找不到了!” 具体是哪些零件呢?错误日志里通常会跟 LNK2001 或 LNK2019 错误,列出找不到的“外部符号”(unresolved external symbol),比如 sscanf, _vsnwprintf, __iob_func, fprintf 这类看着眼熟的 C 标准库函数。

哪儿出问题了?刨根问底

为啥链接器 link.exe 会找不到这些基本函数?主要原因就那么几个:

  1. 编译环境残缺或不匹配: cryptography 这种带 C 扩展的 Python 包,在 Windows 上编译需要 Visual Studio C++ 构建工具。如果你没装,或者装的版本不对(比如你的 Python 是用 VS 2015 编译的,你却只装了 VS 2019 的构建工具),或者安装时没选对必要的组件(比如 C++ 桌面开发工作负载、Windows SDK),那编译链接时就可能缺胳膊少腿。Python 3.5 通常需要 Visual Studio 2015 (VC++ 14.0)。
  2. 依赖库(OpenSSL)配置不当或版本冲突: cryptography 依赖 OpenSSL。你在错误日志里设置了 INCLUDELIB 环境变量,指向了 C:\ProgramData\Runtime\OpenSSL。这很好,但问题是,你这个 OpenSSL 版本是咋来的?它是用跟你当前尝试编译 cryptography 的 Visual Studio 版本兼容的设置编译的吗?特别是,它链接的 C 运行时库(CRT)是啥版本?是多线程静态 (/MT) 还是多线程动态 (/MD)?Debug 版还是 Release 版?如果 Python、cryptography 的 C 扩展、你提供的 OpenSSL 库,它们仨在 CRT 配置上“三观不合”,链接时就互相不认,导致找不到符号。错误日志里提到了 libeay32mt.libssleay32mt.lib,这个 mt 后缀通常暗示是多线程静态库,你需要确认这是否与你的 Python 3.5(通常是动态链接 /MD)兼容。
  3. 环境变量抽风: 虽然你设置了 INCLUDELIB,但有可能 PATH 里有其他冲突的库文件或工具链,或者 vsvars*.bat (设置 VS 编译环境的脚本)没正确运行,导致编译器或链接器用的还是错误的路径或配置。你提供的 PATH 相当长,检查里面是否有多个版本的 VS 工具或 OpenSSL 库路径可能会互相干扰。
  4. Python 版本和目标架构不匹配: 你用的是 64 位的 Windows 和 Python 3.5.0a4 (看起来是 amd64)。编译时要确保使用的是 64 位的 VS 构建工具 (amd64 target),并且链接的库也是 64 位的。你运行 vsvars32.bat,这通常是设置 32 位环境的,可能需要用 vcvarsall.bat amd64 来设置 64 位编译环境。
  5. Visual Studio 2015 和 UCRT 的小坑: VS 2015 开始使用 Universal CRT (UCRT)。有些旧代码或库(比如你手动提供的 OpenSSL)在链接到 UCRT 时,可能需要特定的 Windows SDK 版本或者链接 legacy_stdio_definitions.lib 这类库来解决 __iob_func, sscanf 等函数的缺失问题。

对症下药:解决方案走起

别慌,咱们一步步来试试看能不能搞定。

方案一:拥抱 Wheel,告别编译(推荐)

最省事儿的办法,就是别在本地编译了,直接用别人预编译好的二进制包 (Wheel, .whl 文件)。

  • 原理: PyPI 上通常会提供针对主流操作系统和 Python 版本的预编译 Wheel 包。pip 优先下载和安装 Wheel 包,这样就跳过了本地编译 C 扩展的步骤,自然也就没有链接错误了。
  • 操作步骤:
    1. 升级 pip、setuptools 和 wheel 到最新版,它们对 Wheel 支持更好:
      python -m pip install --upgrade pip setuptools wheel
      
    2. 然后,直接尝试安装 cryptography
      pip install cryptography
      
      pip 会自动查找适合你环境(Windows x64, Python 3.5)的 Wheel 包。如果找到了,安装会很快完成,直接跳过编译环节。
  • 注意:
    • 对于比较老旧或者非稳定版(比如你的 Python 3.5.0a4)的 Python,可能找不到对应的 Wheel 包,pip 还是会尝试源码编译。
    • 网络环境不好的话,下载 Wheel 包可能失败。

方案二:配齐配对编译环境

如果找不到 Wheel,或者你非要从源码编译不可,那就得确保编译环境是“原配”的。

  • 原理: 保证 Python、Visual Studio C++ 构建工具、OpenSSL 库三者的版本和配置(尤其是 CRT 链接方式)相互兼容。

  • 操作步骤:

    1. 确认并安装正确的 Visual Studio 构建工具:

      • Python 3.5 需要 Visual Studio 2015 (VC++ 14.0)。如果你没装,去微软官网下载 Visual Studio 2015 (Community 版免费) 或 Visual Studio Build Tools 2015。
      • 安装时,务必勾选 "Programming Languages" -> "Visual C++" 下的 "Common Tools for Visual C++ 2015" 和 "Microsoft Foundation Classes (MFC)"。
      • 同时,确保安装了合适的 Windows SDK。VS 2015 安装程序通常会带一个默认的 Windows 10 SDK,包含了 UCRT,这对于链接是必须的。检查“Universal Windows App Development Tools” -> “Windows 10 SDK” 是否安装。
    2. 处理 OpenSSL 依赖(关键):

      • 方法一 (推荐): 移除手动配置,让 cryptography 自己搞定。 很多现代 Python 包(包括较新版的 cryptography)在编译时能够自动处理 OpenSSL 依赖,或者依赖于像 pyOpenSSL 这样也可能提供预编译库的包。先把你手动设置的 INCLUDELIB 环境变量 删掉 试试。
        # 在你的命令行里临时移除环境变量(或者永久修改系统环境变量后重启命令行)
        set INCLUDE=
        set LIB=
        
        然后尝试 pip install cryptography
      • 方法二: 获取兼容的 OpenSSL 预编译库。 如果非要手动指定 OpenSSL,你需要找到一个明确是用 Visual Studio 2015 (VC14)64位 (x64) 编译的,并且 动态链接 CRT (/MD) 的 OpenSSL 版本。可以去一些提供 Windows 版 OpenSSL 预编译库的网站找(比如 Shining Light Productions ,注意选择正确的 VC 版本和架构)。下载后,解压,然后 确保 你设置的 INCLUDE 指向 include 目录,LIB 指向包含 .lib 文件的 lib 目录(不要 指向 lib\VC\static 那个静态库目录,除非你百分百确定需要静态链接且知道如何处理 CRT 冲突)。
    3. 清理环境,使用正确的 VS 环境启动脚本:

      • 删掉之前的编译残留。可以运行 pip cache purge 清理 pip 缓存。手动删除 S:\Temp\Local\ 下的 pip-build-* 目录。
      • 最好在 Python 虚拟环境里操作,避免污染全局环境。
        # 创建虚拟环境 (如果还没创建)
        python -m venv myenv
        # 激活虚拟环境
        myenv\Scripts\activate
        
      • 启动正确的 VS 编译环境。 不要用 vsvars32.bat。打开 "VS 2015 x64 Native Tools Command Prompt" (或者在普通 CMD 里运行 vcvarsall.bat amd64) 来配置 64 位编译环境。
        # 在已经安装了 VS 2015 的机器上,这个命令应该能配置好环境
        "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
        
        运行后,检查 INCLUDE, LIB, PATH 环境变量是否包含了 VS 14.0 和 Windows SDK 的 x64 路径。
    4. 重新尝试编译安装:

      • 正确配置好的 VS 编译环境 的命令行里(虚拟环境也已激活),并且已经处理好 OpenSSL (要么移除手动设置,要么设置了正确的兼容库路径),再次尝试安装。可以加上 --no-binary :cryptography: 强制编译,以便测试你的编译环境是否真的配好了。
        pip install cryptography --no-binary :cryptography:
        
  • 安全建议: 从非官方渠道下载 OpenSSL 预编译库时,要确认来源的可信度。

方案三:升级 Python 版本

和过时的、还是 Alpha 版的 Python 3.5.0a4 死磕可能得不偿失。

  • 原理: 新版本的 Python (例如 Python 3.7+) 通常对 Windows 编译环境的支持更好,其依赖的 Visual Studio 版本也更现代 (比如 Python 3.7-3.9 依赖 VS 2017,3.10+ 依赖 VS 2019 或更高),相关的生态(包括 cryptography 的 Wheel 包)也更完善。
  • 操作步骤:
    1. Python 官网 下载一个最新的稳定版 Python (比如 3.9, 3.10, 3.11 等,检查 cryptography 对 Python 版本的支持)。
    2. 安装新 Python,记得勾选 "Add Python to PATH"。
    3. 为新 Python 创建一个新的虚拟环境。
    4. 在新环境里,升级 pip 工具后直接尝试 pip install cryptography。大概率能直接找到 Wheel 包并成功安装。

方案四:换个环境试试?(WSL 或 Docker)

如果 Windows 环境下 C 扩展编译总是让你头疼,可以考虑在更“友好”的环境中开发。

  • 原理: Linux 环境下通常 C 编译器和库的管理更直接方便。WSL (Windows Subsystem for Linux) 或 Docker 容器能提供一个 Linux 环境。
  • WSL:
    • 启用 WSL 功能,安装一个 Linux 发行版 (如 Ubuntu)。
    • 在 WSL 的 Linux 环境里安装 Python 和 pip,然后 pip install cryptography 通常会顺利很多,因为它可能使用系统自带的 OpenSSL 开发库,或者编译过程更顺畅。
  • Docker:
    • 编写一个 Dockerfile,基于官方 Python 镜像,在里面用 RUN pip install cryptography 来安装。这样可以构建一个包含所有依赖的隔离环境。
  • 适宜性: 这两种方式需要额外学习成本,改变了开发流程,看是否适合你的项目和习惯。

通常来说,优先尝试 方案一 (使用 Wheel) ,简单高效。如果不行,仔细检查并配置好 方案二 (编译环境) 是解决 link.exe 报错的根本途径,尤其是 OpenSSL 库的兼容性问题。方案三 (升级 Python) 是一个非常务实的建议,可以避免很多历史遗留问题。方案四则是改变环境的大招。

希望这些方法能帮你摆脱 link.exe failed with exit status 1120 的困扰!