Создание расширений 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 для создания и упаковки модулей расширения доступна в Распространение модулей Python (старая версия). Если вы обнаружите, что вам действительно нужно делать все вручную, может быть полезно изучить файл проекта модуля 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 КБ. Чтобы избавиться от них, воспользуйтесь диалогом «Настройка проекта», вкладкой «Связывание», чтобы указать «Игнорировать стандартные библиотеки». Добавьте правильные msvcrtxx.lib в список библиотек.
© 2001–2023 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.10/extending/windows.html