Создание расширений 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; оно предоставляет доступ к именам модуля, но не создает отдельную копию. В 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()), но знает, как найти код 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–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/extending/windows.html