【问题标题】:What is the best way to deal with "_d" suffix for C extensions when using debug build?使用调试构建时处理 C 扩展的“_d”后缀的最佳方法是什么?
【发布时间】:2015-04-10 05:49:36
【问题描述】:

我正在尝试为 Python 2.7 调试我的 C 扩展。我使用 python2.7 调试版本。我用setuptools 构建我的项目,而我的setup.py 有这样的行:

ext_modules=[Extension("my.extension",
                       ["my/_extension.c"])]

当我出于某种原因调用python setup.py install 时,扩展程序会编译为带有_d 后缀的文件,然后在Python 中,我不能执行import my.extension,我只能执行import my.extension_d。而我得到的是:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "build/bdist.linux-x86_64/egg/my/extension_d.py", line 7, in <module>
  File "build/bdist.linux-x86_64/egg/my/extension_d.py", line 6, in __bootstrap__
ImportError: dynamic module does not define init function (initextension_d)

当然我的扩展没有initextension_d,它只有initextension功能。

这很不方便,因为我必须更改一些代码并将这个_d 后缀添加到导入和其他内容中。

是否可以关闭此后缀的前置?或者如何以其他方式处理该问题?也许有一些“官方”的方式?

更新 #0

我使用 Ubuntu Linux。

【问题讨论】:

  • 你在什么平台上看到这个?您的回溯提到linux。 Windows 是唯一使用_d 进行调试构建的平台。请参阅下面我尝试为 Windows 平台提供答案(您可能不是故意的)。
  • 你应该发布python setup.py install的输出。
  • 可能还有setup.py 本身和os.name 的值。我也想知道.py 扩展。它应该由.pyd.so ...

标签: python python-c-api python-c-extension


【解决方案1】:

在构建 C 扩展时禁用调试模式。 或者,如果您想保留调试信息,请暂时禁用 _DEBUG 宏:

#ifdef _DEBUG
# ifndef BOOST_DEBUG_PYTHON
#  ifdef _MSC_VER  
    // VC8.0 will complain if system headers are #included both with
    // and without _DEBUG defined, so we have to #include all the
    // system headers used by pyconfig.h right here.
#   include <stddef.h>
#   include <stdarg.h>
#   include <stdio.h>
#   include <stdlib.h>
#   include <assert.h>
#   include <errno.h>
#   include <ctype.h>
#   include <wchar.h>
#   include <basetsd.h>
#   include <io.h>
#   include <limits.h>
#   include <float.h>
#   include <string.h>
#   include <math.h>
#   include <time.h>
#  endif
#  undef _DEBUG // Don't let Python force the debug library just because we're debugging.
#  define DEBUG_WRAP_PYTHON_H
# endif
#endif

#include <Python.h>

#ifdef DEBUG_WRAP_PYTHON_H
# define _DEBUG
#endif

对于完整的代码示例,您可以查看 full version,了解 boost.python 如何包含 python.h

【讨论】:

    【解决方案2】:

    要解决这个问题,你可以在你的 C 模块中定义函数

    void initextension_d()
    { initextension(); }
    

    【讨论】:

    • @fpbhb 你为什么这么认为?
    • 因为您最终会将扩展的调试版本加载到使用互不兼容的运行时库的解释器的非调试版本中。我试图在我的回答中解释这一点。
    • @fpbhb 引用您的回答:话虽如此,没有必要使用 Python 的调试版本来调试 Python 扩展,除非您打算使用 msvcrtd.dll 的调试功能 你为什么决定作者使用 Visual C++ 编译器?
    • 显然是因为 Windows 是唯一一个 Python 扩展模块在调试版本中以不同名称命名的平台(添加 _d)。 OTOH,你是对的,问题在回溯中提到了linux-x86……也许我们应该问提问者?
    • ...也许“Gill Bates”也让我想到了“Windows”;-)
    【解决方案3】:

    来自 build_ext.py 的 distutils 源文件的注释:

    #debug_mode 中的扩展在 windows 下被命名为 'module_d.pyd'

    C 扩展也是一样,所以应该没有问题。不过既然有,也可以去掉_d后缀:

    import os.path
    from setuptools.command.build_ext import build_ext as _build_ext
    
    class build_ext(_build_ext):
        def get_ext_filename(self, ext_name):
            fn = _build_ext.get_ext_filename(self, ext_name)
            fn = os.path.splitext(fn)
            if fn[0].endswith('_d'):
                fn[0] = fn[0][:-2]
            return fn[0] + fn[1]
    

    或者只是暂时禁用调试:

    from setuptools.command.build_ext import build_ext as _build_ext
    
    class build_ext(_build_ext):
        def get_ext_filename(self, ext_name):
            debug, self.debug = self.debug, False
            fn = _build_ext.get_ext_filename(self, ext_name)
            self.debug = debug
            return fn
    

    不要忘记在setup 中设置cmdclass

    setup(
        ...
        cmdclass={'build_ext': build_ext},
        ...
    )
    

    我自己没有使用 Windows,所以这只是一个疯狂的猜测,但也许你正在混合 Python 的调试和发布部分。

    【讨论】:

      猜你喜欢
      • 2013-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-30
      • 1970-01-01
      • 2010-09-06
      • 2021-11-18
      • 1970-01-01
      相关资源
      最近更新 更多