Создание расширений C и C++ на Windows
В этой главе кратко объясняется, как создать модуль расширения для Python на Windows с использованием 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: использовать пакет setuptools для управления процессом сборки или выполнять действия вручную. Подход setuptools хорошо подходит для большинства расширений; документация по использованию setuptools для создания и упаковки модулей расширения доступна в Создание расширений C и C++ с помощью setuptools. Если вам действительно нужно выполнять действия вручную, полезно изучить файл проекта модуля стандартной библиотеки 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++; использование других компиляторов может или может не работать. Остальная часть этого раздела специфична для 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 добавит много библиотек импорта, которые вам на самом деле не нужны, увеличивая размер вашего исполняемого файла примерно на 100 КБ. Чтобы избавиться от них, используйте диалоговое окно "Настройки проекта", вкладку "Линковка", чтобы указать ignore default libraries. Добавьте правильную msvcrtxx.lib в список библиотек.
© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/extending/windows.html