1

我正在尝试调试一个在 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))

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

这是故意的吗?我看到一个旧的错误报告,似乎表明稳定 ABI 不受调试版本的约束。(这就是我在 SO 上发布而不是提交错误报告的原因)

如果是故意的,是否希望我先链接 python35_d.lib,然后再链接 python35.lib,还是有其他方法可以解决这个问题?

4

1 回答 1

5

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

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

config/auto_link.hpp

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

#pragma comment(lib, string_of_library_name)

-- 在 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

并比较两者。主要区别在于发布版本导出符号 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

赠品在 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

解决方案是构建专门链接 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 threading=multi variant=debug address-model=64 --with-python --debug-configuration python-debugging=on stage

请注意,要解决依赖关系,您还必须编译 date_time、thread、chrono、filesystem 和 system(只需将“--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 调用的脚本加载时不会崩溃。

于 2016-08-29T04:50:45.263 回答