Pythonをexe化する方法（Pyinstaller・Nuitka）

# はじめに
今回は社内ツールの開発で利用したPythonのexe化ライブラリ2種について書いていきます。
半ば自分用のメモでもあるので、わかりにくかったらすいません。

### exe化とは
 Pythonで開発したツールは、Pythonのない環境では動かせません。使っているライブラリもインストールする必要があります。なので、同じようにPython環境を用意していない人に共有するのは一筋縄ではいきません。
 そこで役に立つのがexe化です。Pythonスクリプトをexeファイル(Windowsの実行ファイル)に変換することで、Python環境なしでも同じような動作をさせることができます。

## Pyinstallerについて
Pythonのexe化について調べると、最初に見つかるライブラリがPyinstallerです。自分も最初はこれを使いました。
>PyInstaller は、Python アプリケーションとそのすべての依存関係を 1 つのパッケージにバンドルします。ユーザーは、Python インタープリターやモジュールをインストールしなくても、パッケージ化されたアプリを実行できます。 PyInstaller は Python 3.8 以降をサポートし、numpy、matplotlib、PyQt、wxPython などの多くの主要な Python パッケージを正しくバンドルします。
>[公式サイトより引用](https://pyinstaller.org/en/stable/)

試しに使ってみましょう。
```test.py
print("Hello World")
```
みんな大好きHelloWorld君です。
用意した同フォルダで以下のコマンドを実行しましょう。
```console
PS C:\vscode\python_test> pyinstaller test.py
```

元々あったtest.py以外にいくつかファイルが作成されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2088977/738387cf-7b8e-1b0b-8241-3748aa43e1b3.png)
以下はChatGPTに聞いてみた各ファイルの内容です。

---
### `dist` ディレクトリ

### 役割

- このディレクトリには、PyInstallerによって生成された実行可能ファイルと、アプリケーションの実行に必要な全ての依存ファイルが含まれます。
- アプリケーションを配布する際には、この`dist`ディレクトリ内の内容をユーザーに提供します。

### 内容

- 実行可能ファイル
- 依存するDLLファイル
- Pythonライブラリ
- データファイルなど

### `build` ディレクトリ

### 役割

- `build`ディレクトリは変換プロセス中にPyInstallerが使用する一時ファイルを格納します。
- ビルドプロセスのデバッグやトラブルシューティングに役立つ情報が含まれます。

### 内容

- 中間ファイル
- ログファイル
- 解析されたバイナリファイルなど

### `.spec` ファイル

### 役割

- PyInstallerがアプリケーションをコンパイルする際に参照する設定ファイルです。
- ビルドプロセスの細かいカスタマイズを可能にします。

### 内容

- 追加のファイルやディレクトリの指定
- 隠されたインポートの追加
- アイコン設定
- 単一ファイルモードやウィンドウモードの指定など

---


あっさり言うと、完成品がdistフォルダに格納されることが分かっていればOKだと思います。
```console
PS C:\vscode\python_test\dist\test> .\test.exe
Hello World
```
### --onefileオプションについて
distフォルダはexeファイル以外にもファイルが形成されています。それらも実行に必要なファイルなので、人に渡す際はフォルダごと渡す必要があります。
それは面倒ですよね、ということでよく使われるのが`--onefile`オプション
```console
PS C:\vscode\python_test> pyinstaller test.py --onefile
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2088977/07f29482-4384-596c-9496-70a86fe9cfd3.png)
これで中身がexeファイルのみになりました。
他にもオプションは色々あるようなので、気になる方は調べてください。

## Pyinstallerの問題点
これで楽に共有ができる！と思って、ちゃんとしたツールを作成し、exe化したところで、Pyinstallerの大きな問題点に直面しました。
### ライブラリ重い問題
ライブラリを色々入れてみた状態で`pyinstaller --onefile`をやりましょう。
```test.py
import numpy
import pyautogui
import pandas
import pyppeteer
print("Hello World")
```
容量はこんな感じになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2088977/22b50910-ed63-c325-7780-8827bfa3bd8e.png)
問題なのは起動時間です。
ライブラリ無し：一瞬
ライブラリ有り：2秒くらい
これ、簡単な処理の場合はこれくらいで済むのですが、処理を色々と連ねていくと、起動時間が数十秒にも伸びていきます。
実際、ツール作成時では起動に20秒以上かかってしまい、exe化について見直すに至りました。
## Nuitkaについて
続いては同じくexe化ライブラリ Nuitkaについて
Pyinstallerに比べて人気は少なめですね。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2088977/2bfc2448-76fa-bb56-2da8-5fd1433fdfcd.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2088977/c2a4cafb-f6af-16d9-dc39-96634d97707d.png)

`--standalone`オプションを付けることでPython無し環境でも動くよう作れるみたいです。
```console
PS C:\vscode\nuitka_test> nuitka --standalone test.py
```
2024/03/26現在はPython3.12が最新ですが、Nuitkaは3.11まで対応となっています。
```console
PS C:\vscode\python_test> nuitka --standalone test.py
Nuitka-Options: Used command line options: --standalone test.py
Nuitka:WARNING: The Python version '3.12' is only experimentally supported by Nuitka '2.1.3', but an upcoming release will change that. In the mean time use Python version '3.11' instead or newer Nuitka.
FATAL: The Python version '3.12' is not supported by Nuitka '2.1.3', but an upcoming release will add it. In the mean time use '3.11' instead.
```

暫くしたら対応されそうですね。
とりあえずpython3.11に変更しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2088977/b21ebf86-aee4-043f-92d2-78b3049f39f0.png)
Pyinstallerとは異なり、test.buildとtest.distが作成されました。
distフォルダの中身が完成品です。

同じように`--onefile`オプションはあるので、一ファイルにまとめたい場合は使ってみましょう。
ちなみに容量はそこまで変わりませんでした。(35,754 KB)

#### Pyinstallerと比べると
##### メリット
- 起動が早い
- 実行速度も速い

Nuitkaは一度C言語に変換して、それからコンパイルが行われるので、比較的速度が速いようです。
社内ツール作成時に利用した時も、起動が確実に速くなりました。
##### デメリット
- コンパイルに時間がかかる（特に`--onefile`付けた場合）
- `--onefile`オプションで社内ソフトにウイルス判定された…

コンパイルは極端に長くなります。Pyinstallerでは1分程度で出来たものも、Nuitkaでは30分以上かかることがありました。

## 結局どっち使ったのか
最終的に、社内ツールの共有には`Nuitka --standalone`を使いました。
`--onefile`オプションも使いたかったのですが、ウイルス誤検知や起動時間の関係で、使わないことになりました。
コンパイルに時間はかかりますが、頻繁な更新はしないので別にいいかなと思いました。
今後も社内共有で利用していきたいと思います。