4. 构建 C/C++ 扩展
******************

CPython 的 C 扩展是一个共享库 (例如 Linux 上的 ".so"，或者 Windows上的
".pyd")，其会导出一个 *初始化函数*。

为了可导入，共享库必须在 "PYTHONPATH" 中列出，且必须按照模块名称命名，
并带有正确的扩展名。 当使用 setuptools 时，会自动生成正确的文件名。

初始化函数的声明如下：

PyObject *PyInit_modulename(void)

该函数返回完整初始化过的模块，或一个 "PyModuleDef" 实例。 请查看 初始
化 C 模块 了解详情。

对于名称仅包含 ASCII 字符的模块，函数必须被命名为 "PyInit_*<name>*"，
其中的 "<name>" 将使用模块的名称来替换。 当使用 多阶段初始化 时，模块
名称允许包含非 ASCII 字符。 在此情况下，初始化函数名称为
"PyInitU_*<name>*"，其中的 "<name>" 将使用 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。 请参考
https://setuptools.readthedocs.io/en/latest/setuptools.html 上的
"setuptools" 文档来更多地了解如何使用 setuptools 来构建和分发 C/C++ 扩
展。
