如何解决 AMD64 Win Python35_d.lib 中缺少 PyModule_Create2 的问题?

Pet*_* Du 1 c python python-c-api python-c-extension debug-mode

我正在尝试调试一个在 32 位 Python 2.7 中运行良好的扩展模块,但在 64 位 Python 3.5 中却不是那么好。

我使用了 Python.org 的 AMD64 Web 安装程序,但在我得到的链接中

__imp_PyModule_Create2 (referenced in libboost_python-vc120-mt-gd-1_57.lib(module.obj))
Run Code Online (Sandbox Code Playgroud)

未解决。这是唯一未解决的符号。

这是故意的吗?我看到一个旧的错误报告,它似乎表明稳定 ABI 免于调试版本。(这就是为什么我在 SO 上发帖而不是提交错误报告)

如果是故意的,是否预计我会先与 python35_d.lib 链接,然后与 python35.lib 链接,还是有另一种方法来解决这个问题?

Pet*_* Du 5

我在这里发现了这个问题;AMD64 因素无关紧要。

关键是 Boost Python 库希望链接到 Python 的 Release 版本,即使它是 Boost Python 的调试版本。通过尝试链接依赖于 Boost Python 的扩展模块,Boost 的

config/auto_link.hpp
Run Code Online (Sandbox Code Playgroud)

将(默认情况下)创建一个链接依赖——使用

#pragma comment(lib, string_of_library_name)
Run Code Online (Sandbox Code Playgroud)

-- 在 python35.lib 上。如果您在扩展模块的 makefile 中指定了 python35_d.lib,并期望您的 python 将作为 python35_d.exe 调用,那么这是个坏消息。

我通过运行找到了这个

dumpbin /EXPORTS python35.lib > python35_exp.txt
dumpbin /EXPORTS python35_d.lib > python35_d_exp.txt
Run Code Online (Sandbox Code Playgroud)

并比较两者。主要区别在于发布版本导出符号 PyModule_Create2 和 PyModule_FromDefAndSpec2,而调试版本导出 PyModule_Create2TraceRefs 和 PyModule_FromDefAndSpec2TraceRefs。这显然是 Python 开发人员故意选择的,以确保调试扩展模块仅适用于调试 Python。在 Python 源代码中,include/object.h 中的第一行之一是

/* Py_DEBUG implies Py_TRACE_REFS. */
#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS)
#define Py_TRACE_REFS
#endif
Run Code Online (Sandbox Code Playgroud)

赠品在 include/modsupport.h

#ifdef Py_TRACE_REFS
 /* When we are tracing reference counts, rename module creation functions so
    modules compiled with incompatible settings will generate a
    link-time error. */
 #define PyModule_Create2 PyModule_Create2TraceRefs
 #define PyModule_FromDefAndSpec2 PyModule_FromDefAndSpec2TraceRefs
#endif
Run Code Online (Sandbox Code Playgroud)

解决方案是构建专门链接 python35_d.lib 的 Boost 库的特殊版本。涉及到几个步骤:

  • 运行 'bootstrap.bat --with-python="C:\Program Files\Python35"'
  • 在您的主目录中编辑 user-config.jam,使其看起来像(空格很重要)
    使用 python : 3.5 : C:\\PROGRA~1\\Python35 ;
    使用 python : 2.7 : C:\\Python27 ;
    使用 python : 3.5 : C:\\PROGRA~1\\Python35\\python_d
      : # 包括
      :#库
      : <python-debugging>on ;
  • 使用额外选项“python-debugging=on”调用 b2.exe,就像这样
.\b2.exe 工具集=msvc-12.0 线程=多变体=调试地址-模型=64 --with-python --debug-configuration python-debugging=on stage

请注意,要解决依赖关系,您还必须编译 date_time、线程、计时、文件系统和系统(只需将“--with-python”替换为“--with-otherlibname”。)

  • 最后一步是确保您正在构建链接的扩展模块针对“正确的”库。我发现定义预处理器符号 BOOST_DEBUG_PYTHON 和 BOOST_LINKING_PYTHON 以及预期的 _DEBUG 就足够了,因为在 config/auto_link.hpp 中有这些行
    # 如果已定义(_DEBUG) && 已定义(BOOST_DEBUG_PYTHON) && 已定义(BOOST_LINKING_PYTHON)
    # 定义 BOOST_LIB_RT_OPT "-gyd"
    # elif 定义(_DEBUG)
    # 定义 BOOST_LIB_RT_OPT "-gd"
    # 别的
    # 定义 BOOST_LIB_RT_OPT
    # 万一

应该这样做 - 一个 Python 扩展模块的调试版本,它应该编译并链接到一个 Boost Python 库,该库期望链接到 python35_d.lib,并且在被使用 python_d.exe 调用的脚本加载时不会崩溃。