В Windows регистрация расширения .pyz
не является обязательной и кроме того, есть определенные моменты, при которых зарегистрированные расширения не распознаются "прозрачно". Самый простой пример команда subprocess.run(['myapp'])
не найдет приложение и нужно явно указать расширение .pyz
. Поэтому в Windows часто предпочтительнее из zipapp
создать исполняемый файл. Это относительно просто, хотя для этого нужен компилятор языка Си.
Основной подход основан на том факте, что к zip-файлам могут добавляться произвольные данные и к файлам exe
в Windows так же могут добавляться произвольные данные. Поэтому, создав подходящий модуль запуска и прикрепив файл приложения .pyz
к его концу, можно получить исполняемый файл, который будет нормально работать в Windows.
Подходящий модуль запуска может быть таким:
#define Py_LIMITED_API 1 #include "Python.h" #define WIN32_LEAN_AND_MEAN #include <windows.h> #ifdef WINDOWS int WINAPI wWinMain( HINSTANCE hInstance, /* Обращение к текущему экземпляру */ HINSTANCE hPrevInstance, /* Обращение к предыдущему экземпляру */ LPWSTR lpCmdLine, /* Указатель на командную строку */ int nCmdShow /* Показать состояние окна */ ) #else int wmain() #endif { wchar_t **myargv = _alloca((__argc + 1) * sizeof(wchar_t*)); myargv[0] = __wargv[0]; memcpy(myargv + 1, __wargv, __argc * sizeof(wchar_t *)); return Py_Main(__argc+1, myargv); }
Если определить препроцессор обработки окон WINDOWS, это сгенерирует исполняемый файл GUI, а без него - исполняемый консольный файл.
Чтобы скомпилировать исполняемый файл, можно либо просто использовать стандартные инструменты командной строки MSVC
, либо воспользоваться тем, что distutils
знает, как скомпилировать исходный код Python:
from distutils.ccompiler import new_compiler import distutils.sysconfig import sys import os from pathlib import Path def compile(src): src = Path(src) cc = new_compiler() exe = src.stem cc.add_include_dir(distutils.sysconfig.get_python_inc()) cc.add_library_dir(os.path.join(sys.base_exec_prefix, 'libs')) # First the CLI executable objs = cc.compile([str(src)]) cc.link_executable(objs, exe) # Now the GUI executable cc.define_macro('WINDOWS') objs = cc.compile([str(src)]) cc.link_executable(objs, exe + 'w') if __name__ == "__main__": compile("zastub.c")
В результате запускается «Limited ABI», поэтому он будет работать без изменений с любой версией Python 3.x. Все, что ему нужно, это чтобы Python python3.dll
был в PATH
пользователя.
Для полностью автономного дистрибутива вы можете собрать файл инсталятора install.exe
, в котором будут находится дистрибутив Python вместе с приложением, что будет работать на любом ПК с соответствующей архитектурой.