Встраивание Python в Windows: почему он должен быть DLL? - PullRequest
9 голосов
/ 17 октября 2010

Я пытаюсь написать программный плагин, который встраивает Python.В Windows плагин технически является DLL (это может быть актуально). FAQ по Python для Windows гласит:

1.До не встроить Python в ваш файл .exe напрямую.В Windows Python должен быть DLL для обработки импортируемых модулей, которые сами являются DLL.(Это первый ключевой недокументированный факт.) Вместо этого ссылка на pythonNN.dll;обычно он устанавливается в C: \ Windows \ System.NN - это версия Python, например, «23» для Python 2.3.

Мой вопрос: почему именно Python должен быть DLL?Если, как в моем случае, хост-приложение не является .exe, но также и DLL, могу ли я встроить в него Python?Или, возможно, это примечание означает, что сторонние расширения C полагаются на pythonN.N.dll для присутствия, а другие DLL не подойдут?Предполагая, что я действительно хочу иметь одну DLL, что мне делать?

Я вижу, что есть файл dynload_win.c, который, по-видимому, является модулем для импорта расширений C наWindows и, насколько я вижу, сканирует файл расширения, чтобы найти, какой pythonX.X.dll он импортирует;но у меня нет опыта работы с Windows, и я не совсем понимаю весь код там.

Ответы [ 4 ]

4 голосов
/ 17 октября 2010

Вам нужно связать pythonXY.dll как DLL, вместо того, чтобы связывать соответствующий код непосредственно с исполняемым файлом, потому что в противном случае среда выполнения Python не сможет загрузить другие DLL (модули расширения, на которые она опирается).) Если вы создаете свою собственную DLL, вы можете теоретически связать весь код Python в этой DLL напрямую, так как он не попадает в исполняемый файл, но все еще в DLL.Однако вам придется позаботиться о том, чтобы правильно выполнить связывание, поскольку практически ни один из стандартных инструментов (например, distutils) не сделает это за вас.

Однако независимо от того, как вы встраиваете Python, вы можетене обойтись с просто DLL, и вы не можете обойтись только с любой DLL.ABI меняется между версиями Python, поэтому, если вы скомпилировали свой код для Python 2.6, вам понадобится python26.dll;Вы не можете использовать python25.dll или python27.dll.И Python - это не просто DLL;ему также нужна стандартная библиотека, которая включает модули расширения (которые сами являются DLL, хотя они имеют расширение .pyd). Код в dynload_win.c, с которым вы столкнулись, предназначен для загрузки этих DLL, ине имеет отношения к загрузке pythonXY.dll.

Короче говоря, чтобы встроить Python в плагин, вам необходимо либо отправить Python вместе с плагином, либо потребовать, чтобы была установлена ​​правильная версия Python.

2 голосов
/ 18 октября 2010

(Извините, я сделал глупость, сначала написал вопрос, а затем зарегистрировался, и теперь я не могу изменить его или прокомментировать ответы, потому что движок StackOverflow не считает меня автором. Я даже не могудолжным образом поблагодарите тех, кто ответил :( Так что это фактически обновление к вопросу и комментариям.)

Спасибо за все советы, это очень ценно. Насколько я понимаю, с некоторыми усилиями я могу статически связать Python впользовательская библиотека DLL, при условии, что я сам собираю другие динамически загруженные расширения и связываю их с той же библиотекой DLL. (Я знаю, что мне нужно также поставить стандартную библиотеку; мой план заключался в добавлении архива в формате DLL в файл DLL. Насколько яПонимаю, я даже смогу импортировать из него чистые модули Python.)

Я также нашел интересное место в dynload_win.c. (насколько я понимаю, он загружает динамические расширения, использующие Python C API, например, _ctypes.) Насколько я вижу, он не только ищет символ init_ctypes или какое-либо другое имя расширения, но также сканирует .pyd.Таблица импорта файла ищет (regex) python\d+\., а затем сравнивает найденный символ с известной строкой pythonNN., чтобы убедиться, что расширение было скомпилировано для этой версии Python.Если таблица импорта не имеет такого символа или относится к другой версии, возникает ошибка.

Для меня это означает, что:

  • Если я свяжу расширение с pythonNN.dll и попытаюсь загрузить его из моей пользовательской библиотеки DLL, которая включает в себя статически связанный Python, она пройдетпроверить, но - ну, здесь я не уверен: произойдет ли сбой, потому что нет pythonNN.dll (т.е. даже до того, как попасть на проверку), или он с радостью загрузит символы?
  • И если я свяжу этопротив моей пользовательской библиотеки DLL, он найдет символы, но не пройдет проверку :) Я думаю, я мог бы переписать этот кусок в соответствии со своими потребностями ... Есть ли еще такие места, яИнтересно.
1 голос
/ 18 октября 2010

В * nix все общие объекты в процессе, включая исполняемый файл, вносят свои экспортированные имена в общий пул; любой из совместно используемых объектов может затем извлечь любые имена из пула и использовать их по своему усмотрению. Это позволяет, например, cStringIO.so для извлечения соответствующих функций библиотеки Python из основного исполняемого файла, когда библиотека Python статически связана.

В Windows каждый общий объект имеет свой собственный независимый пул имен, которые он может использовать. Это означает, что он должен читать соответствующие различные общие объекты, от которых ему нужны функции. Поскольку для получения всех имен из основного исполняемого файла требуется много работы, функции Python разделены на свои собственные DLL.

1 голос
/ 18 октября 2010

Python должен быть dll (со стандартным именем), чтобы ваше приложение и плагин могли использовать один и тот же экземпляр python.

Библиотеки плагинов уже ожидают загрузки (и использования python from) файла python26.dll (или любой другой версии) - если ваш python статически встроен в ваш exe, то два разных экземпляра библиотеки pythonбудет управлять теми же структурами данных.

Если библиотеки Python вообще не используют статические переменные, а параметры компиляции равны точно , это не должно быть проблемой.Однако, как правило, гораздо безопаснее просто использовать только один экземпляр интерпретатора python.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...