【问题标题】:Building a Python-C-Extension on Windows with a debug Python installation使用调试 Python 安装在 Windows 上构建 Python-C 扩展
【发布时间】:2019-12-01 15:01:39
【问题描述】:

如果我在 Windows 上从源代码构建 CPython,当我想 pip 安装包含 C 扩展的包时会遇到问题。链接库时似乎发生了错误。

例如在安装 cython 时(但它也会在其他 C 扩展包上崩溃并出现相同的错误):

LINK : 致命错误 LNK1104: 无法打开文件 'python38.lib'

错误:命令 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.23.28105\bin\HostX86\x86\link.exe' 失败,退出状态为 1104

无法打开“python38.lib”的原因是调试模式下的“.lib”文件名为“python38_d.lib”。

基于Quick Reference of the CPython developer guide 的最小可重现示例是(在命令行上):

git clone --branch v3.8.0 https://github.com/python/cpython.git
cd cpython
git checkout v3.8.0
.\PCbuild\build.bat -e -d
.\PCbuild\win32\python_d.exe -m ensurepip
.\PCbuild\win32\python_d.exe -m pip install pip --upgrade -vv
.\PCbuild\win32\python_d.exe -m pip install setuptools --upgrade -vv
.\PCbuild\win32\python_d.exe -m pip install cython -vv

生成的distutils.sysconfig.get_config_vars() 是:

{'BINDIR': '...\\cpython\\PCbuild\\win32',
 'BINLIBDEST': ...\\cpython\\Lib',
 'EXE': '.exe',
 'EXT_SUFFIX': '_d.cp38-win32.pyd',
 'INCLUDEPY': '...\\cpython\\include;...\\cpython\\PC',
 'LIBDEST': '...\\cpython\\Lib',
 'SO': '_d.cp38-win32.pyd',
 'VERSION': '38',
 'exec_prefix': '...\\cpython',
 'prefix': '...\\cpython',
 'srcdir': '...\\cpython'}

我有什么遗漏吗?是否不支持在 Windows 上的 Python 调试版本上构建 C 扩展?如果支持:我会怎么做?

【问题讨论】:

  • Distutils 从配置中获取信息。不确定您的设置如何。这是一个示例如何推翻设置文件中的设置stackoverflow.com/a/57057959/5769463
  • @ead 您是指 CPython 配置还是我尝试安装的扩展模块中的配置?也不应该默认选择 CPython 构建选项(并且我想安装的模块之一在设置中基本上不包含自定义) - 那么为什么它没有意识到它必须链接到 python38_d.lib?我在我的计算机和 CI 上测试了问题中的命令,但它们都失败了。如果您有解决方法或建议如何解决此问题,我将不胜感激:)
  • 我的意思是 distutils.config。您可以检查提供的值并查看问题所在。遗憾的是,接下来的几天我将无法调查这个问题
  • @ead 感谢您的澄清。我在问题中包含了值。

标签: python pip setuptools cpython python-c-api


【解决方案1】:

这段代码有点hacky,但在MSVC19上对我有用,允许在不构建调试python库的情况下调试应用程序。

#ifdef _DEBUG
#define _DEBUG_WAS_DEFINED
#undef _DEBUG
#endif

#include "Python.h"

#ifdef _DEBUG_WAS_DEFINED
#define _DEBUG
#undef _DEBUG_WAS_DEFINED
#endif

【讨论】:

    【解决方案2】:

    在 Windows 上链接 pythonXY.lib 有点偷偷摸摸。当您查看用于链接的命令行时,您会看到没有将 python 库传递给链接器,即“link.exe”。注意:Linux 也是如此,但在 Linux 上不必这样做,因为所需的符号将由 python 可执行文件提供。

    但是,to check viadumpbin /dependents resulting.pyd 很容易,对 pythonXY.dll 存在依赖关系,还将 extra_link_args = ["/VERBOSE:LIB"] 添加到 extension-definition 并触发链接器的详细模式将显示链接器使用 @987654332 @。

    鬼鬼祟祟的部分:Microsoft Compler 有一个 convinience-pragma #pragma comment(lib, ...) 来自动触发库的链接,这也被用于in Python-headers

    #               if defined(_MSC_VER)
                            /* So MSVC users need not specify the .lib
                            file in their Makefile (other compilers are
                            generally taken care of by distutils.) */
    #                       if defined(_DEBUG)
    #                               pragma comment(lib,"python39_d.lib")
    #                       elif defined(Py_LIMITED_API)
    #                               pragma comment(lib,"python3.lib")
    #                       else
    #                               pragma comment(lib,"python39.lib")
    #                       endif /* _DEBUG */
    #               endif /* _MSC_VER */
    

    如您所见,要链接到调试版本,需要定义_DEBUG

    _DEBUG 在 Windows 上由 distutils 自动定义,如果使用选项 --debug 调用 build_ext,例如

    python setup.py build_ext -i --debug
    

    那可以是translated to pip

    pip install --global-option build --global-option --debug XXXXX
    

    可以粗略解释为:在安装之前使用选项--debug 触发build 命令(其中还包括build_ext-command)。


    构建调试 C 扩展时的另一个微妙之处,有more to it on Windows

    #ifdef _DEBUG
    #       define Py_DEBUG
    #endif
    

    定义了Py_DEBUG 宏意味着不兼容的ABIs until Python3.8,因为它还假定Py_TRACE_REFS 导致PyObject 的不同内存布局以及释放模式中缺少一些附加功能。

    但是,从 Python3.8 开始,人们可能可以通过提供缺少的 pythonXY_d.lib/pythonYX.lib 作为链接到另一个版本的符号链接来摆脱它。

    【讨论】:

    • 您知道您的回答中的哪些部分可能是投反对票的原因吗?它适用于我的用例,其余的答案对我来说很有意义 - 所以我想知道可能存在哪些问题/缺点。
    • @MSeifert 我不知道,但如果有人能指出问题,将不胜感激。
    猜你喜欢
    • 2019-05-16
    • 1970-01-01
    • 1970-01-01
    • 2021-06-16
    • 1970-01-01
    • 2021-05-10
    • 1970-01-01
    • 1970-01-01
    • 2020-11-11
    相关资源
    最近更新 更多