5. Создание расширений C и C++ в Windows¶
В этой главе кратко объясняется, как создать модуль расширения Windows для Python с помощью Microsoft Visual C++, а также приводится более подробная справочная информация о его работе. Пояснительный материал полезен как для программиста Windows, учившегося строить расширения Python, так и для программиста Unix, заинтересованного в производстве программного обеспечения, которое может быть успешно построено как на Unix, так и на Windows.
Авторам модулей рекомендуется использовать distutils подход для построения модулей расширения вместо описанного в этом разделе. Компилятор C, который был используемый для построения Python, все равно понадобится; обычно Microsoft Visual C++.
Примечание
Эта глава упоминает много имен файлов, которые включают номер версии кодированный
Python. Эти имена файлов представлены номером версии, показанным как
XY
; на практике 'X'
будет основным номером версии, а 'Y'
- младшим номером версии Python выпуска, с которым вы работаете. Например,
если используется Python 2.2.1, XY
будет фактически 22
.
5.1. Подход к кулинарной книге¶
Существует два подхода к построению модулей расширения в Windows, как и в Unix:
использовать пакет distutils
для управления процессом сборки или выполнять
вручную. Подход distutils хорошо подходит для большинства расширений;
документация по использованию модулей расширения distutils
для сборки и
упаковки доступна в Distributing Python Modules (Legacy version). Если вам действительно нужно сделать что-то
вручную, может быть поучительно изучить файл проекта для
winsound модуля стандартной библиотеки.
5.2. Различия между Unix и Windows¶
Unix и Windows используют совершенно разные парадигмы для загрузки кода во время выполнения. Перед созданием модуля, который может быть динамически загружен, необходимо знать, как работает система.
В Unix файл общих объектов (.so
) содержит код, подлежащие
используемый программой, а также имена функций и данные, которые она рассчитывает
найти в программе. Когда файл прилинкован к программе, все ссылки на эти функции
и данные в коде файла изменяются, указывая на фактические местоположения
в программе, где функции и данные помещаются в память. В основном это операция
линковки.
В Windows файл динамически подключаемой библиотеки (.dll
) не имеет висячих
ссылок. Вместо этого доступ к функциям или данным проходит через таблицу
экспорта. Таким образом, код DLL не должен быть исправлен во время
выполнения, чтобы обратиться к памяти программы; вместо этого код уже
использует таблицу экспорта DLL и таблица экспорта изменяется во время
выполнения, указывая на функции и данные.
В Unix существует только один тип файла библиотеки (.a
), который
содержит код из нескольких файлов объектов (.o
). На этапе
создания общего файла объекта (.so
) линковщик может обнаружить, что он
не знает, где определен идентификатор. линковщик будет искать его в файлах
объектов в библиотеках; если он найдет его, он будет включать все код из
этого файла объекта.
В Windows существует два типа библиотек: статическая библиотека и библиотека
импорта (оба называются .lib
). Статическая библиотека похожа на файл Unix
.a
; он содержит код, которые необходимо включить. Библиотека
импорта в основном используется только для того, чтобы подтвердить линковщику,
что определенный идентификатор является законным, и будет присутствовать в
программе при загрузке DLL. Поэтому линковщик использует информацию из
библиотеки импорта для построения таблицы экспорта с использованием
идентификаторов, не включенных в DLL. Когда приложение или библиотека DLL
связаны, может быть создана библиотека импорта, которая должна быть используемый
для всех будущих библиотек DLL, которые зависят от символов в приложении или
библиотеке DLL.
Предположим, что вы собираете два динамически загружаемых модуля, B и C, которые
должны совместно использовать другой блок кода A. В Unix вы не
передаете A.a
линкеру для B.so
и C.so
; это приведет к
тому, что он будет включен дважды, так что B и C будут иметь свои собственные
копии. в Windows, сборка A.dll
также будет строить A.lib
. Вы
передаете A.lib
линкеру для B и C. A.lib
не содержит
код; он просто содержит информацию, которая будет использоваться во время
выполнения для доступа к код A.
В Windows использование импортируемой библиотеки подобно использованию import spam
;
она дает вам доступ к именам spam, но не создает отдельной копии. в Unix связь
с библиотекой больше похожа на from spam import *
; создается отдельная копия.
5.3. Использование DLL на практике¶
Windows Python встроена в Microsoft Visual C++; использование других компиляторов может работать или не работать (хотя Borland кажется). Остальная часть этого раздела относится к MSVC++.
При создании DLL в Windows необходимо передать pythonXY.lib
линкеру. Чтобы
построить две DLL, spam и ni (которые используют функции C, найденные в spam),
можно использовать эти команды:
cl /LD /I/python/include spam.c ../libs/pythonXY.lib
cl /LD /I/python/include ni.c spam.lib ../libs/pythonXY.lib
Первая команда создала три файла: spam.obj
, spam.dll
и spam.lib
.
Spam.dll
не содержит каких-либо Python функций (таких как PyArg_ParseTuple()
),
но умеет находить Python код благодаря pythonXY.lib
.
Вторая команда создала ni.dll
(и .obj
и .lib
), которая умеет
находить необходимые функции из spam, а также из Python исполняемого
файла.
Не каждый идентификатор экспортируется в таблицу экспорта. Если вы хотите,
чтобы другие модули (включая Python) могли видеть ваши идентификаторы, вы
должны сказать _declspec(dllexport)
, как в void _declspec(dllexport) initspam(void)
или PyObject _declspec(dllexport) *NiGetSpamData(void)
.
Developer Studio вложит в исполняемый файл множество библиотек импорта, которые
вам не очень нужны, добавляя около 100K. Чтобы избавиться от них, укажите
игнорировать библиотеки по умолчанию в диалоговом окне «Параметры проекта» на вкладке «Связь». Добавьте
правильный msvcrtxx.lib
в список библиотек.