windows.md
1> **Источник:** https://python-all.ru/3.4/extending/windows.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 4. Сборка расширений C и C++ в Windows89В этой главе кратко объясняется, как создать модуль расширения для Windows на Python с помощью Microsoft Visual C++, после чего приводится более подробная справочная информация о том, как это работает. Материал полезен как программисту Windows, осваивающему сборку расширений Python, так и программисту Unix, заинтересованному в создании программного обеспечения, которое успешно собирается как на Unix, так и на Windows.1011Авторам модулей рекомендуется использовать подход distutils для сборки модулей расширения вместо описанного в этом разделе. При этом всё равно понадобится компилятор C, который использовался для сборки Python; обычно это Microsoft Visual C++.1213> **Примечание**14>15> В этой главе упоминается ряд имен файлов, содержащих закодированный номер версии Python. Эти имена файлов представлены с номером версии в виде `XY`; на практике `'X'` – это номер старшей версии, а `'Y'` – номер младшей версии используемого выпуска Python. Например, если вы используете Python 2.2.1, `XY` на самом деле будет `22`.1617## 4.1. Подход «Кулинарная книга»1819Существует два подхода к сборке модулей расширения в Windows, как и в Unix: использовать пакет [`distutils`](https://python-all.ru/3.4/library/distutils.html#module-distutils) для управления процессом сборки или делать всё вручную. Подход с distutils хорошо подходит для большинства расширений; документация по использованию [`distutils`](https://python-all.ru/3.4/library/distutils.html#module-distutils) для сборки и упаковки модулей расширения доступна в [*Distributing Python Modules (Legacy version)*](https://python-all.ru/3.4/distutils/index.html#distutils-index). Если вы обнаружите, что действительно нужно делать всё вручную, возможно, будет полезно изучить файл проекта для модуля стандартной библиотеки [winsound](https://python-all.ru/src/3.4/PCbuild/winsound.vcxproj).2021## 4.2. Различия между Unix и Windows2223В Unix и Windows используются совершенно разные парадигмы загрузки кода во время выполнения. Прежде чем пытаться собрать модуль, который может загружаться динамически, следует понимать, как работает ваша система.2425В Unix файл shared object (`.so`) содержит код для использования программой, а также имена функций и данных, которые он ожидает найти в программе. Когда файл присоединяется к программе, все ссылки на эти функции и данные в коде файла изменяются, чтобы указывать на фактические расположения в памяти программы, где размещены функции и данные. По сути, это операция компоновки.2627В Windows файл динамической библиотеки (DLL) (`.dll`) не имеет висячих ссылок. Вместо этого доступ к функциям или данным осуществляется через таблицу поиска. Таким образом, код DLL не нужно корректировать во время выполнения для обращения к памяти программы; вместо этого код уже использует таблицу поиска DLL, а сама таблица изменяется во время выполнения, чтобы указывать на нужные функции и данные.2829В Unix существует только один тип библиотечного файла (`.a`), который содержит код из нескольких объектных файлов (`.o`). На этапе компоновки для создания файла shared object (`.so`) компоновщик может обнаружить, что не знает, где определён идентификатор. Компоновщик будет искать его в объектных файлах библиотек; если найдёт, он включит весь код из этого объектного файла.3031В Windows существует два типа библиотек: статическая библиотека и библиотека импорта (обе называются `.lib`). Статическая библиотека похожа на файл `.a` в Unix; она содержит код, который будет включён по мере необходимости. Библиотека импорта в основном используется только для подтверждения компоновщику, что определённый идентификатор является допустимым и будет присутствовать в программе при загрузке DLL. Таким образом, компоновщик использует информацию из библиотеки импорта для построения таблицы поиска для идентификаторов, которые не включены в DLL. Когда приложение или DLL компонуется, может быть создана библиотека импорта, которая понадобится для всех будущих DLL, зависящих от символов из этого приложения или DLL.3233Предположим, вы собираете два модуля динамической загрузки, B и C, которые должны совместно использовать другой блок кода A. В Unix вы бы *не* передавали `A.a` компоновщику для `B.so` и `C.so`; это привело бы к его включению дважды, так что B и C имели бы по собственной копии. В Windows сборка `A.dll` также создаст `A.lib`. Вы *действительно* передаёте `A.lib` компоновщику для B и C. `A.lib` не содержит код; он содержит только информацию, которая будет использоваться во время выполнения для доступа к коду A.3435В Windows использование библиотеки импорта отчасти похоже на использование `import spam`; это даёт доступ к именам из spam, но не создаёт отдельную копию. В Unix компоновка с библиотекой больше похожа на `from spam import *`; она создаёт отдельную копию.3637## 4.3. Использование DLL на практике3839Python для Windows собирается в Microsoft Visual C++; использование других компиляторов может работать или не работать (хотя Borland, похоже, работает). Остальная часть этого раздела относится только к MSVC++.4041При создании DLL в Windows необходимо передавать `pythonXY.lib` компоновщику. Чтобы собрать две DLL, spam и ni (которая использует функции C из spam), можно использовать следующие команды:4243```c44cl /LD /I/python/include spam.c ../libs/pythonXY.lib45cl /LD /I/python/include ni.c spam.lib ../libs/pythonXY.lib46```4748Первая команда создала три файла: `spam.obj`, `spam.dll` и `spam.lib`. `Spam.dll` не содержит никаких функций Python (таких как [`PyArg_ParseTuple()`](https://python-all.ru/3.4/c-api/arg.html#c.PyArg_ParseTuple)), но благодаря `pythonXY.lib` он знает, как найти код Python.4950Вторая команда создала `ni.dll` (а также `.obj` и `.lib`), который знает, как найти необходимые функции из spam, а также из исполняемого файла Python.5152Не каждый идентификатор экспортируется в таблицу поиска. Если вы хотите, чтобы другие модули (включая Python) могли видеть ваши идентификаторы, необходимо указать `_declspec(dllexport)`, например `void _declspec(dllexport) initspam(void)` или `PyObject _declspec(dllexport) *NiGetSpamData(void)`.5354Developer Studio добавит много ненужных библиотек импорта, увеличив размер исполняемого файла примерно на 100 КБ. Чтобы избавиться от них, в диалоге Project Settings на вкладке Link укажите *ignore default libraries*. Добавьте правильную `msvcrtxx.lib` в список библиотек.55