Содержание страницы
5. Сборка расширений 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.
5.1. Подход с рецептами¶A Cookbook Approach
Существует два подхода к сборке модулей расширения в Windows, как и в Unix: использовать пакет setuptools для управления процессом сборки или делать всё вручную. Подход setuptools хорошо работает для большинства расширений; документация по использованию setuptools для сборки и упаковки модулей расширения доступна в Сборка расширений C и C++ с помощью setuptools. Если вы обнаружите, что вам действительно нужно делать всё вручную, может быть полезно изучить файл проекта для модуля стандартной библиотеки winsound.
5.2. Различия между Unix и Windows¶Differences Between Unix and Windows
В Unix и Windows используются совершенно разные парадигмы загрузки кода во время выполнения. Прежде чем пытаться собрать модуль, который может загружаться динамически, следует понимать, как работает ваша система.
В Unix файл shared object (.so) содержит код, который будет использоваться программой, а также имена функций и данных, которые он ожидает найти в программе. Когда файл присоединяется к программе, все ссылки на эти функции и данные в коде файла изменяются так, чтобы указывать на фактические адреса в памяти программы, где размещены функции и данные. По сути, это операция компоновки.
В Windows файл динамически подключаемой библиотеки (.dll) не содержит висячих ссылок. Вместо этого доступ к функциям и данным осуществляется через таблицу поиска. Таким образом, код DLL не требует исправлений во время выполнения для ссылок на память программы; вместо этого код уже использует таблицу поиска DLL, а таблица поиска изменяется во время выполнения, чтобы указывать на функции и данные.
В Unix существует только один тип файла библиотеки (.a), который содержит код из нескольких объектных файлов (.o). На этапе компоновки для создания shared object файла (.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 на практике¶Using DLLs in Practice
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 КБ. Чтобы избавиться от них, в диалоговом окне Project
Settings на вкладке Link следует указать ignore default libraries. Затем добавить правильную msvcrtxx.lib в список
библиотек.