building.md
1> **Источник:** https://python-all.ru/3.10/extending/building.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 4. Сборка расширений на C и C++89Расширение C для CPython – это разделяемая библиотека (например, файл `.so` в Linux, `.pyd` в Windows), которая экспортирует *функцию инициализации*.1011Чтобы её можно было импортировать, общая библиотека должна быть доступна по [`PYTHONPATH`](https://python-all.ru/3.10/using/cmdline.html#envvar-PYTHONPATH) и должна иметь имя, соответствующее имени модуля, с подходящим расширением. При использовании distutils правильное имя файла генерируется автоматически.1213Функция инициализации имеет следующую сигнатуру:1415#### `PyObject *PyInit_modulename(void)`1617Функция возвращает либо полностью инициализированный модуль, либо экземпляр [`PyModuleDef`](https://python-all.ru/3.10/c-api/module.html#c.PyModuleDef). Подробнее см. в разделе [Инициализация модулей C](https://python-all.ru/3.10/c-api/module.html#initializing-modules).1819Для модулей, имена которых содержат только ASCII, функция должна называться `PyInit_<modulename>`, где `<modulename>` заменяется именем модуля. При использовании [многофазной инициализации](https://python-all.ru/3.10/c-api/module.html#multi-phase-initialization) допускаются имена модулей, не являющиеся ASCII. В этом случае имя функции инициализации – `PyInitU_<modulename>`, где `<modulename>` закодировано с помощью кодировки *punycode* языка Python, причём дефисы заменены символами подчёркивания. В Python:2021```python22def initfunc_name(name):23 try:24 suffix = b'_' + name.encode('ascii')25 except UnicodeEncodeError:26 suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')27 return b'PyInit' + suffix28```2930It is possible to export multiple modules from a single shared library by defining multiple initialization functions. However, importing them requires using symbolic links or a custom importer, because by default only the function corresponding to the filename is found. See the *“Multiple modules in one library”* section in [**PEP 489**](https://python-all.ru/3.10/extending/building.html) for details.3132## 4.1. Сборка расширений на C и C++ с помощью distutils3334Модули-расширения можно собирать с помощью distutils, который входит в состав Python. Поскольку distutils также поддерживает создание двоичных пакетов, пользователям не обязательно нужен компилятор и distutils для установки расширения.3536Пакет distutils содержит управляющий скрипт `setup.py`. Это обычный файл Python, который в простейшем случае может выглядеть так:3738```python39from distutils.core import setup, Extension4041module1 = Extension('demo',42 sources = ['demo.c'])4344setup (name = 'PackageName',45 version = '1.0',46 description = 'This is a demo package',47 ext_modules = [module1])48```4950Имея этот `setup.py` и файл `demo.c`, при выполнении5152```c53python setup.py build54```5556скомпилирует `demo.c` и создаст модуль-расширение с именем `demo` в каталоге `build`. В зависимости от системы файл модуля окажется в подкаталоге `build/lib.system` и может иметь имя вроде `demo.so` или `demo.pyd`.5758В `setup.py` все выполнение осуществляется вызовом функции `setup`. Она принимает переменное количество именованных аргументов, из которых вышеприведённый пример использует только часть. В частности, пример задаёт метаинформацию для сборки пакетов и определяет содержимое пакета. Обычно пакет содержит дополнительные модули, такие как исходные модули Python, документацию, вложенные пакеты и т.д. Обратитесь к документации distutils в [Distributing Python Modules (Legacy version)](https://python-all.ru/3.10/distutils/index.html#distutils-index), чтобы узнать больше о возможностях distutils; в этом разделе объясняется только сборка модулей-расширений.5960Часто аргументы для `setup()` вычисляют заранее, чтобы лучше структурировать управляющий скрипт. В примере выше аргумент `ext_modules` для [`setup()`](https://python-all.ru/3.10/distutils/apiref.html#distutils.core.setup) представляет собой список модулей-расширений, каждый из которых является экземпляром `Extension`. В примере экземпляр определяет расширение с именем `demo`, которое собирается компиляцией одного исходного файла, `demo.c`.6162Во многих случаях сборка расширения сложнее, поскольку могут потребоваться дополнительные определения препроцессора и библиотеки. Это показано в примере ниже.6364```python65from distutils.core import setup, Extension6667module1 = Extension('demo',68 define_macros = [('MAJOR_VERSION', '1'),69 ('MINOR_VERSION', '0')],70 include_dirs = ['/usr/local/include'],71 libraries = ['tcl83'],72 library_dirs = ['/usr/local/lib'],73 sources = ['demo.c'])7475setup (name = 'PackageName',76 version = '1.0',77 description = 'This is a demo package',78 author = 'Martin v. Loewis',79 author_email = 'martin@v.loewis.de',80 url = 'https://docs.python.org/extending/building',81 long_description = '''82This is really just a demo package.83''',84 ext_modules = [module1])85```8687В этом примере [`setup()`](https://python-all.ru/3.10/distutils/apiref.html#distutils.core.setup) вызывается с дополнительной метаинформацией, что рекомендуется при сборке дистрибутивных пакетов. Для самого расширения указываются определения препроцессора, каталоги включаемых файлов, каталоги библиотек и сами библиотеки. В зависимости от компилятора distutils передаёт эту информацию компилятору разными способами. Например, в Unix это может привести к командам компиляции:8889```c90gcc -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -fPIC -DMAJOR_VERSION=1 -DMINOR_VERSION=0 -I/usr/local/include -I/usr/local/include/python2.2 -c demo.c -o build/temp.linux-i686-2.2/demo.o9192gcc -shared build/temp.linux-i686-2.2/demo.o -L/usr/local/lib -ltcl83 -o build/lib.linux-i686-2.2/demo.so93```9495Эти строки приведены только для демонстрации; пользователи distutils должны доверять, что distutils правильно формирует вызовы.9697## 4.2. Распространение модулей-расширений9899После успешной сборки расширения есть три способа его использования.100101Конечные пользователи обычно хотят установить модуль; они делают это, выполняя102103```c104python setup.py install105```106107Сопровождающие модуля должны создавать исходные пакеты; для этого они выполняют108109```c110python setup.py sdist111```112113В некоторых случаях в исходный дистрибутив нужно включить дополнительные файлы; это делается через файл `MANIFEST.in`; подробнее см. [Specifying the files to distribute](https://python-all.ru/3.10/distutils/sourcedist.html#manifest).114115Если исходный дистрибутив собран успешно, сопровождающие также могут создавать двоичные дистрибутивы. В зависимости от платформы для этого можно использовать одну из следующих команд.116117```c118python setup.py bdist_rpm119python setup.py bdist_dumb120```121