【问题标题】:How is a C extension compiled with the correct native calling convention?如何使用正确的本机调用约定编译 C 扩展?
【发布时间】:2020-07-27 12:37:16
【问题描述】:

假设我们正在用 C 语言编写一个 CPython 扩展模块。

定义扩展时,我们需要提供PyMODINIT_FUNC PyInit_<module_name>(void)。此声明中没有指定本地调用约定。

无论是在 Linux 上还是在 Windows 上,扩展开发人员如何确保 PyInit_ 函数使用正确的调用约定编译,以便解释器在运行时成功调用它? Python 头文件中是否有一些魔法可以为我们解决这个问题?还是别的什么?

同样的问题也适用于扩展模块中包含的原生函数,并且暴露给 Python 包装为函数对象。我们如何确保以与 Python 解释器调用约定兼容的方式编译它们?

【问题讨论】:

    标签: c cpython calling-convention


    【解决方案1】:

    默认调用约定由编译器自动制定。 PyMODINIT_FUNCvoid(在 Python 2 中)或 PyObject *(在 Python 3 中),仅此而已。

    Python 动态模块加载器使用平台的默认约定(并不是说它对此有任何管辖权;它属于平台)。

    【讨论】:

      【解决方案2】:

      您实际上是在写PyMODINIT_FUNC PyInit_<module_name>(void)。现在PyMODINIT_FUNC 是一个宏,可以扩展为由pyport.h 中的各种#ifdefs 控制的不同事物。在 Github 修订版中的当前 HEAD 修订版中,Python 3.9 开发版有这 6 个定义:

      #define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject*
      #define PyMODINIT_FUNC PyObject*
      #define PyMODINIT_FUNC extern "C" Py_EXPORTED_SYMBOL PyObject*
      #define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject*
      #define PyMODINIT_FUNC extern "C" Py_EXPORTED_SYMBOL PyObject*
      #define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject*
      

      即它扩展为 PyObject * 作为返回类型,但如果使用 C++ 编译器编译以确保针对此符号的 C 链接,则扩展为 extern "C"并且在某些平台上包括 Py_EXPORTED_SYMBOL

      Py_EXPORTED_SYMBOLexports.h 中定义为

      #define Py_EXPORTED_SYMBOL __declspec(dllexport)
      #define Py_EXPORTED_SYMBOL __attribute__ ((visibility ("default")))
      #define Py_EXPORTED_SYMBOL
      

      这些都没有指定调用约定,而是让函数默认为 cdecl 约定,因为它们应该...... - 还请注意,调用约定大多仅在 Windows 中存在。

      【讨论】:

        猜你喜欢
        • 2011-05-06
        • 1970-01-01
        • 2018-12-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多