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 для сборки и упаковки модулей расширения доступна в Распространение модулей Python (версия Legacy). Если вы обнаружите, что вам действительно нужно все делать вручную, может быть полезно изучить файл проекта для модуля стандартной библиотеки 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 на практике

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), которая знает, как найти необходимые функции из спама, а также из исполняемого файла Python.

Не каждый идентификатор экспортируется в таблицу поиска. Если вы хотите, чтобы другие модули (включая Python) могли видеть ваши идентификаторы, вы должны сказать _declspec(dllexport), как в void _declspec(dllexport) initspam(void) или PyObject _declspec(dllexport) *NiGetSpamData(void).

Developer Studio добавит множество библиотек импорта, которые вам на самом деле не нужны, добавив около 100K к вашему исполняемому файлу. Чтобы избавиться от них, используйте диалог Project Settings, вкладка Link, чтобы указать ignore default libraries. Добавьте нужные msvcrtxx.lib в список библиотек.

Вернуться на верх