4. 构建C/C++扩展¶
一个CPython的C扩展是一个共享库(例如一个Linux上的 .so
,或者Windows上的 .pyd
),其会导出一个 初始化函数 。
To be importable, the shared library must be available on PYTHONPATH
,
and must be named after the module name, with an appropriate extension.
When using setuptools, the correct filename is generated automatically.
初始化函数的声明如下:
It returns either a fully initialized module, or a PyModuleDef
instance. See Initializing C modules for details.
对于仅有ASCII编码的模块名,函数必须是 PyInit_<modulename>
,将 <modulename>
替换为模块的名字。当使用 Multi-phase initialization 时,允许使用非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. Building C and C++ Extensions with setuptools¶
Python 3.12 and newer no longer come with distutils. Please refer to the
setuptools
documentation at
https://setuptools.readthedocs.io/en/latest/setuptools.html
to learn more about how build and distribute C/C++ extensions with setuptools.