Open for new projects · sublimearts.io
← Blog
Windows Dev10 июня 2026·12 мин. чтения

Компиляция автономных Python-исполняемых файлов с Nuitka для устранения накладных расходов.

Исчерпывающее руководство по выпуску сверхбыстрых .exe-файлов для Windows без медленных пакетов времени выполнения вроде PyInstaller. Именно так ReelNox Studio и BackDrop_ доставляются реальным пользователям — со всеми ошибками, которые я сделал по пути.

Нравится статья? В конце вас ждёт ❤️.

Зачем вообще компилировать Python

Если вы делаете настольное приложение на Python и хотите, чтобы его мог запустить обычный человек, «pip install» — не вариант. У него не установлен Python, он не хочет его устанавливать и не должен этого делать. Нужен настоящий .exe, на который можно дважды щёлкнуть. Для этого нужна компиляция — превращение вашего интерпретируемого Python-кода и его зависимостей во что-то, что запускается без установленного Python на целевой машине.

Почему PyInstaller оказался недостаточно хорош

PyInstaller был первой попыткой, и он работает — технически. Проблема в том, что он делает на самом деле: упаковывает интерпретатор Python и все ваши зависимости в пакет, а затем распаковывает их во временную папку при каждом запуске приложения (режим --onefile) или поставляет в виде папки с россыпью файлов (режим --onedir). В обоих случаях при запуске вы всё равно выполняете интерпретируемый байт-код через встроенную среду выполнения Python, а не скомпилированный машинный код. Запуск ощущался вялым, шаг распаковки во временную папку добавлял заметную задержку при первом старте, а антивирусы считают «распаковывается в %TEMP% и начинает выполняться» хрестоматийной эвристикой вредоносного ПО — это вызвало именно ту проблему ложных срабатываний, которой я хотел избежать.

Правильный подход: Nuitka --standalone

Nuitka — это настоящий компилятор Python в C. Он не упаковывает интерпретатор: он переводит ваш Python-код в C, компилирует его настоящим C-компилятором и линкует в самый обычный нативный исполняемый файл. Результат работает как скомпилированный машинный код, а не как интерпретируемый байт-код внутри встроенной среды. Запуск почти мгновенный, и, что принципиально, во время работы он никогда не распаковывается во временную папку, что убирает главный триггер антивирусных эвристик. Самый важный флаг — --standalone: он создаёт самодостаточную папку с вашим .exe и его нативными зависимостями рядом, готовую к распространению как есть или к упаковке в установщик.

Как это сделать на практике

1Установите Nuitka: pip install nuitka (на машине нужен компилятор C — на Windows это MSVC, который установщик Nuitka может скачать за вас, если Visual Studio Build Tools у вас ещё нет)
2Запустите компиляцию: python -m nuitka --standalone --enable-plugin=tk-inter --windows-console-mode=disable --output-dir=dist main.py
3Nuitka создаст папку dist/main.dist/ с main.exe и всеми обнаруженными нативными зависимостями — распространять нужно всю эту папку, а не только .exe
4Оберните эту папку установщиком (я использую Inno Setup), чтобы пользователи получили обычную установку Windows, а не папку с россыпью файлов
5Протестируйте установленное приложение на чистой виртуальной машине Windows без Python до выпуска — это единственный способ поймать отсутствующую DLL или путь к ресурсам, который работал только на вашей машине разработки

3 ошибки, которые стоили мне часов

⚠️ Забыть --enable-plugin=tk-inter

Если ваш интерфейс использует Tkinter или CustomTkinter, а вы пропустите этот флаг, скомпилированное приложение не выдаст громкой ошибки — оно просто не загрузит GUI-библиотеку и может молча упасть или показать пустое окно. Nuitka по умолчанию не включает поддержку GUI-фреймворков; её нужно включать отдельно для каждого фреймворка.

⚠️ Использовать --onefile вместо --standalone

--onefile соблазняет тем, что даёт один .exe вместо папки. Не используйте его для всего, что собираетесь распространять публично. Сборки onefile всё равно распаковываются во временный каталог при запуске — то самое поведение, из-за которого PyInstaller вызывал ложные срабатывания, — и я видел, как Windows Defender помечал их как Wacatac или Sabsik только из-за такого шаблона распаковки при совершенно чистом коде. --standalone полностью этого избегает.

⚠️ Определять пути к ресурсам через __file__ вместо sys.executable

В обычном Python-скрипте __file__ указывает на расположение вашего исходного файла. В скомпилированной автономной сборке это допущение не работает. Используйте Path(sys.executable).parent, чтобы узнать, где на машине пользователя на самом деле лежит ваш .exe, и загружайте конфигурационные файлы, значки и упакованные ресурсы относительно него, а не относительно того места, где исходники случайно лежали во время разработки.

Что это даёт на самом деле

И ReelNox Studio, и BackDrop_ выпускаются как сборки Nuitka --standalone, подписанные сертификатом DigiCert EV. Запуск мгновенный, Windows Defender не помечает ни один из установщиков, и ни одному из приложений никогда не требовалась упакованная среда Python, о которой пользователю приходилось бы думать. Важна именно комбинация: --standalone (а не --onefile) плюс правильная подпись кода — вместе они решают и проблему производительности, и проблему доверия, которые сопровождают распространение Python-приложения как нативного исполняемого файла Windows.

Посмотреть в работе → ReelNox StudioСобрано с Nuitka --standalone, GPU-ускорение, подпись EV

About

Патрик Чен — независимый разработчик Sublimearts.io. Здесь — о реальных проблемах сборки, возникших при выпуске ReelNox Studio, BackDrop_ и Time Precision для настоящих пользователей Windows, а не об общих туториалах.

Did you find this helpful?