Сборка расширений 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. Практический подход
Как и в Unix, в Windows есть два подхода к сборке модулей расширения: использовать пакет 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). Статическая библиотека похожа на файл .a в Unix: она содержит код, который при необходимости включается в программу. Библиотека импорта нужна, по сути, только для того, чтобы заверить компоновщик, что определённый идентификатор допустим и будет доступен в программе после загрузки DLL. Поэтому компоновщик использует сведения из библиотеки импорта для создания таблицы поиска, позволяющей использовать идентификаторы, которые не включены в DLL. При компоновке приложения или DLL может быть создана библиотека импорта, которую потребуется использовать при сборке всех будущих DLL, зависящих от символов приложения или DLL.
Предположим, вы создаёте два динамически загружаемых модуля, B и C, которые должны использовать общий блок кода A. В Unix вы не передавали бы A.a компоновщику для B.so и C.so: в результате код был бы включён дважды, и у B и C появились бы собственные копии. В Windows сборка A.dll также создаст A.lib. Компоновщику для B и C нужно передать A.lib. A.lib не содержит кода; в нём содержатся лишь сведения, которые будут использоваться во время выполнения для доступа к коду A.
В Windows использование библиотеки импорта чем-то похоже на использование import spam: оно предоставляет доступ к именам spam, но не создаёт отдельную копию. В Unix компоновка с библиотекой больше похожа на from spam import *: она действительно создаёт отдельную копию.
5.3. Практическое использование DLL
Версия Python для Windows собирается с помощью 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()), но благодаря pythonXY.lib умеет находить код Python.
Вторая команда создала ni.dll (а также .obj и .lib), которая умеет находить необходимые функции как в spam, так и в исполняемом файле Python.
Не каждый идентификатор экспортируется в таблицу поиска. Если вы хотите, чтобы другие модули (включая Python) могли видеть ваши идентификаторы, необходимо указать _declspec(dllexport), как в void _declspec(dllexport) initspam(void) или PyObject _declspec(dllexport) *NiGetSpamData(void).
Developer Studio добавит множество библиотек импорта, которые на самом деле не нужны, увеличив размер исполняемого файла примерно на 100 КБ. Чтобы удалить их, откройте диалоговое окно Project Settings, вкладку Link, и выберите ignore default libraries. Добавьте в список библиотек правильное значение msvcrtxx.lib.
© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/extending/windows.html