4. 构建 C 和 C++ 扩展

CPython 的 C 扩展是一个共享库(例如,Linux 上的 .so 文件,Windows 上的 .pyd 文件),它导出一个初始化函数

为了可以导入,该共享库必须在 PYTHONPATH 上可用,并且必须以模块名命名,并带有适当的扩展名。 当使用 setuptools 时,会自动生成正确的文件名。

初始化函数的签名如下

PyObject *PyInit_modulename(void)

它返回一个完全初始化的模块,或者一个 PyModuleDef 实例。有关详细信息,请参阅初始化 C 模块

对于仅包含 ASCII 字符的模块名称,该函数必须命名为 PyInit_<modulename>,其中 <modulename> 替换为模块的名称。 当使用多阶段初始化时,允许使用非 ASCII 模块名称。 在这种情况下,初始化函数名称为 PyInitU_<modulename>,其中 <modulename> 使用 Python 的 *punycode* 编码进行编码,并将连字符替换为下划线。 在 Python 中

def initfunc_name(name):
    try:
        suffix = b'_' + name.encode('ascii')
    except UnicodeEncodeError:
        suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')
    return b'PyInit' + suffix

通过定义多个初始化函数,可以从单个共享库导出多个模块。 但是,导入它们需要使用符号链接或自定义导入器,因为默认情况下只会找到与文件名对应的函数。 有关详细信息,请参阅 PEP 489 中的 “一个库中的多个模块” 部分。

4.1. 使用 setuptools 构建 C 和 C++ 扩展

Python 3.12 及更高版本不再附带 distutils。请参考 setuptools 的文档 https://setuptools.readthedocs.io/en/latest/setuptools.html,以了解更多关于如何使用 setuptools 构建和分发 C/C++ 扩展的信息。