Содержание страницы
4. Сборка расширений на C и C++¶Building C and C++ Extensions
Расширение C для CPython – это разделяемая библиотека (например, файл .so в Linux,
.pyd в Windows), которая экспортирует функцию инициализации.
Чтобы её можно было импортировать, общая библиотека должна быть доступна по PYTHONPATH
и должна иметь имя, соответствующее имени модуля, с подходящим расширением.
При использовании distutils правильное имя файла генерируется автоматически.
Функция инициализации имеет следующую сигнатуру:
Функция возвращает либо полностью инициализированный модуль, либо экземпляр PyModuleDef.
Подробнее см. в разделе Инициализация модулей C.
Для модулей, имена которых содержат только ASCII, функция должна называться
PyInit_<modulename>, где <modulename> заменяется именем модуля.
При использовании многофазной инициализации допускаются имена модулей, не являющиеся ASCII.
В этом случае имя функции инициализации –
PyInitU_<modulename>, где <modulename> закодировано с помощью кодировки punycode языка Python, причём дефисы заменены символами подчёркивания.
В 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
It 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 for details.
4.1. Сборка расширений на C и C++ с помощью distutils¶Building C and C++ Extensions with distutils
Модули-расширения можно собирать с помощью distutils, который входит в состав Python. Поскольку distutils также поддерживает создание двоичных пакетов, пользователям не обязательно нужен компилятор и distutils для установки расширения.
Пакет distutils содержит управляющий скрипт setup.py. Это обычный
файл Python, который в простейшем случае может выглядеть так:
from distutils.core import setup, Extension
module1 = Extension('demo',
sources = ['demo.c'])
setup (name = 'PackageName',
version = '1.0',
description = 'This is a demo package',
ext_modules = [module1])
Имея этот setup.py и файл demo.c, при выполнении
python setup.py build
скомпилирует demo.c и создаст модуль-расширение с именем demo в
каталоге build. В зависимости от системы файл модуля окажется
в подкаталоге build/lib.system и может иметь имя вроде
demo.so или demo.pyd.
В setup.py все выполнение осуществляется вызовом функции setup.
Она принимает переменное количество именованных аргументов, из которых
вышеприведённый пример использует только часть. В частности, пример задаёт
метаинформацию для сборки пакетов и определяет содержимое пакета.
Обычно пакет содержит дополнительные модули, такие как исходные модули Python,
документацию, вложенные пакеты и т.д. Обратитесь к документации distutils
в Distributing Python Modules (Legacy version), чтобы узнать больше о возможностях
distutils; в этом разделе объясняется только сборка модулей-расширений.
Часто аргументы для setup() вычисляют заранее, чтобы лучше структурировать
управляющий скрипт. В примере выше аргумент ext_modules для
setup() представляет собой список модулей-расширений, каждый из которых является
экземпляром
Extension. В примере экземпляр
определяет расширение с именем demo, которое собирается компиляцией одного исходного
файла, demo.c.
Во многих случаях сборка расширения сложнее, поскольку могут потребоваться дополнительные определения препроцессора и библиотеки. Это показано в примере ниже.
from distutils.core import setup, Extension
module1 = Extension('demo',
define_macros = [('MAJOR_VERSION', '1'),
('MINOR_VERSION', '0')],
include_dirs = ['/usr/local/include'],
libraries = ['tcl83'],
library_dirs = ['/usr/local/lib'],
sources = ['demo.c'])
setup (name = 'PackageName',
version = '1.0',
description = 'This is a demo package',
author = 'Martin v. Loewis',
author_email = 'martin@v.loewis.de',
url = 'https://docs.python.org/extending/building',
long_description = '''
This is really just a demo package.
''',
ext_modules = [module1])
В этом примере setup() вызывается с дополнительной
метаинформацией, что
рекомендуется при сборке дистрибутивных пакетов. Для самого расширения
указываются определения препроцессора, каталоги включаемых файлов, каталоги
библиотек и сами библиотеки. В зависимости от компилятора distutils передаёт эту
информацию компилятору разными способами. Например, в Unix это может
привести к командам компиляции:
gcc -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.o
gcc -shared build/temp.linux-i686-2.2/demo.o -L/usr/local/lib -ltcl83 -o build/lib.linux-i686-2.2/demo.so
Эти строки приведены только для демонстрации; пользователи distutils должны доверять, что distutils правильно формирует вызовы.
4.2. Распространение модулей-расширений¶Distributing your extension modules
После успешной сборки расширения есть три способа его использования.
Конечные пользователи обычно хотят установить модуль; они делают это, выполняя
python setup.py install
Сопровождающие модуля должны создавать исходные пакеты; для этого они выполняют
python setup.py sdist
В некоторых случаях в исходный дистрибутив нужно включить дополнительные файлы;
это делается через файл MANIFEST.in; подробнее см. Specifying the files to distribute.
Если исходный дистрибутив собран успешно, сопровождающие также могут создавать двоичные дистрибутивы. В зависимости от платформы для этого можно использовать одну из следующих команд.
python setup.py bdist_rpm
python setup.py bdist_dumb