Содержание страницы
4. Сборка расширений C и C++ в Windows¶Building C and C++ Extensions on 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.
4.1. Подход «Кулинарная книга»¶A Cookbook Approach
Существует два подхода к сборке модулей расширения в Windows, как и в Unix: использовать пакет distutils для управления процессом сборки или делать всё вручную. Подход с distutils хорошо подходит для большинства расширений; документация по использованию distutils для сборки и упаковки модулей расширения доступна в Distributing Python Modules (Legacy version). Если вы обнаружите, что действительно нужно делать всё вручную, возможно, будет полезно изучить файл проекта для модуля стандартной библиотеки winsound.
4.2. Различия между Unix и Windows¶Differences Between Unix and Windows
В Unix и Windows используются совершенно разные парадигмы загрузки кода во время выполнения. Прежде чем пытаться собрать модуль, который может загружаться динамически, следует понимать, как работает ваша система.
В Unix файл shared object (.so) содержит код для использования программой, а также имена функций и данных, которые он ожидает найти в программе. Когда файл присоединяется к программе, все ссылки на эти функции и данные в коде файла изменяются, чтобы указывать на фактические расположения в памяти программы, где размещены функции и данные. По сути, это операция компоновки.
В Windows файл динамической библиотеки (DLL) (.dll) не имеет висячих ссылок. Вместо этого доступ к функциям или данным осуществляется через таблицу поиска. Таким образом, код DLL не нужно корректировать во время выполнения для обращения к памяти программы; вместо этого код уже использует таблицу поиска DLL, а сама таблица изменяется во время выполнения, чтобы указывать на нужные функции и данные.
В Unix существует только один тип библиотечного файла (.a), который содержит код из нескольких объектных файлов (.o). На этапе компоновки для создания файла shared object (.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. Вы действительно передаёте A.lib компоновщику для B и C. A.lib не содержит код; он содержит только информацию, которая будет использоваться во время выполнения для доступа к коду A.
В Windows использование библиотеки импорта отчасти похоже на использование import spam; это даёт доступ к именам из spam, но не создаёт отдельную копию. В Unix компоновка с библиотекой больше похожа на from spam import *; она создаёт отдельную копию.
4.3. Использование DLL на практике¶Using DLLs in Practice
Python для Windows собирается в Microsoft Visual C++; использование других компиляторов может работать или не работать (хотя Borland, похоже, работает). Остальная часть этого раздела относится только к 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 в список библиотек.