なぜそもそも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と、そのすぐ隣にあるネイティブ依存ファイルを含む自己完結型のフォルダが生成され、そのまま配布することも、インストーラーで包むこともできます。
実際のやり方
何時間も無駄にした3つの間違い
⚠️ --enable-plugin=tk-interを付け忘れる
GUIにTkinterやCustomTkinterを使っているのにこのフラグを省くと、コンパイルされたアプリは派手なエラーを出さず、GUIツールキットを読み込めないだけで、黙ってクラッシュしたり、空白のウィンドウが表示されたりします。NuitkaはデフォルトではGUIフレームワークのサポートを含めないので、フレームワークごとに明示的に有効にする必要があります。
⚠️ --standaloneではなく--onefileを使う
--onefileはフォルダではなく単一の.exeができるので魅力的です。一般に配布するものには使わないでください。Onefileビルドは実行時に一時ディレクトリへ自己展開するため、PyInstallerで誤検知が起きたのと同じ挙動になります。コードがまったくクリーンでも、その展開パターンだけでWindows DefenderにWacatacやSabsikとして検出されるのを見たことがあります。--standaloneならこれを完全に避けられます。
⚠️ アセットのパスをsys.executableではなく__file__で解決する
通常のPythonスクリプトでは、__file__はソースファイルの場所を指します。コンパイルされたスタンドアロンビルドでは、その前提は崩れます。Path(sys.executable).parentを使って、ユーザーのマシン上で.exeが実際にある場所を求め、設定ファイル、アイコン、同梱アセットをそこからの相対位置で読み込んでください。開発中にたまたまソースがあった場所からの相対ではありません。
これで実際に得られるもの
ReelNox StudioとBackDrop_はどちらもNuitkaの--standaloneビルドとして出荷され、DigiCertのEV証明書でコード署名されています。起動は一瞬で、Windows Defenderはどちらのインストーラーも検出せず、ユーザーが意識しなければならない同梱のPythonランタイムも一度として必要になりませんでした。重要なのは、この組み合わせです。--standalone(--onefileではなく)と適切なコード署名。この2つで、PythonアプリをネイティブなWindows実行ファイルとして配布するときに付いて回るパフォーマンスの問題と信頼の問題の両方が解決します。
About
Patrick Chen — Sublimearts.ioの独立開発者。ReelNox Studio、BackDrop_、Time Precisionを実際のWindowsユーザーに届ける中で、自分が本当にぶつかったビルドの問題について書いています。一般的なチュートリアルではありません。