Spec-Zone.ru › Python 3.10

Создание расширений 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 можно найти в документации distutils в Распространение Python-модулей (старая версия); данный раздел описывает только создание расширений модулей.

Часто аргументы для 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.10/extending/building.html

Spec-Zone.ru

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