Spec-Zone.ru › Python 3.11

Создание расширений C и C++

Расширение на C для CPython — это общая библиотека (например, файл .so в Linux, .pyd в Windows), которая экспортирует функцию инициализации.

Для импорта общая библиотека должна быть доступна в PYTHONPATH и должна иметь имя, соответствующее имени модуля, с соответствующим расширением. При использовании distutils корректное имя файла генерируется автоматически.

Функция инициализации имеет следующий сигнатуру:

PyObject *PyInit_modulename(void)

Она возвращает либо полностью инициализированный модуль, либо экземпляр 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

Возможна экспорт нескольких модулей из одной общей библиотеки путем определения нескольких функций инициализации. Однако для их импорта необходимо использовать символические ссылки или пользовательский импортер, так как по умолчанию находится только функция, соответствующая имени файла. Подробности см. в разделе «Несколько модулей в одной библиотеке» в PEP 489.

4.1. Создание расширений C и C++ с помощью 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 в Распространение модулей Python (старая версия), чтобы узнать больше о возможностях 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. Распространение ваших модулей расширений

Когда расширение успешно создано, есть три способа его использования.

Пользователи обычно хотят установить модуль, для этого они запускают

python setup.py install

Авторы модулей должны создавать пакеты исходных кодов; для этого они запускают

python setup.py sdist

В некоторых случаях необходимо включать дополнительные файлы в пакет исходных кодов; это делается через файл MANIFEST.in; см. Указание файлов для распространения для подробностей.

Если пакет исходных кодов создан успешно, авторы могут также создать бинарные дистрибутивы. В зависимости от платформы можно использовать одну из следующих команд.

python setup.py bdist_rpm
python setup.py bdist_dumb

© 2001–2023 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.11/extending/building.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API