Документация Python неофициальный перевод
Содержание страницы

5. Сборка расширений C и C++ на WindowsBuilding 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 и WindowsDifferences 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 *; она создает отдельную копию.

Отключает неявную компоновку через #pragma с библиотекой Python, выполняемую внутри заголовочных файлов CPython.

Добавлено в версии 3.14.

5.3. Использование DLL на практикеUsing DLLs in Practice

Python для Windows собирается в Microsoft Visual C++; использование других компиляторов может как работать, так и нет. Остальная часть этого раздела относится только к MSVC++.

При создании DLL в Windows можно использовать библиотеку CPython двумя способами:

  1. По умолчанию включение PC/pyconfig.h напрямую или через Python.h запускает неявную, учитывающую конфигурацию компоновку с библиотекой. Заголовочный файл выбирает pythonXY_d.lib для Debug, pythonXY.lib для Release и pythonX.lib для Release с включенным Ограниченным API.

    Чтобы собрать две DLL, spam и ni (которая использует функции C из spam), можно использовать следующие команды:

    cl /LD /I/python/include spam.c
    cl /LD /I/python/include ni.c spam.lib
    

    Первая команда создала три файла: spam.obj, spam.dll и spam.lib. Spam.dll не содержит никаких функций Python (например, PyArg_ParseTuple()), но благодаря неявно скомпонованной pythonXY.lib умеет находить код Python.

    Вторая команда создала ni.dll (а также .obj и .lib), который умеет находить необходимые функции из spam, а также из исполняемого файла Python.

  2. Вручную – определив макрос Py_NO_LINK_LIB перед включением Python.h. Необходимо передать pythonXY.lib компоновщику.

    Чтобы собрать две DLL, spam и ni (которая использует функции C из spam), можно использовать следующие команды:

    cl /LD /DPy_NO_LINK_LIB /I/python/include spam.c ../libs/pythonXY.lib
    cl /LD /DPy_NO_LINK_LIB /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 в список библиотек.