今日も見に来てくださって、ありがとうございます。石川さんです。
今回は、Pythonスクリプトから実行形式の「.exe」ファイルをつくる、というのを書きたいと思います。ずいぶん昔にもお試しでやったことがあったのですけど、どうやるのか、すっかり忘れてしまったので、備忘録的なアレですね。
迷いどころ
実行形式のファイルをつくる方法、ちょっと検索しただけで、山のようにあるのですね。どれを使ったらよいのか、迷います。手元の書籍には、cx_Freezeが紹介されていましたので、それで進めるのがいいのかな、と思っていましたが、最終的には、pyInstallerを使うことに決めました。今はAnaconda3を使っているので、そこに入っているやつがいいなぁ、と調べてみたところ、pyinstallerならcondaコマンドでインストールできそうだったのです。これが決め手ですね。
(base) C:\work>conda search pyinstaller
Loading channels: done
# Name Version Build Channel
pyinstaller 3.4 py27h7a46e7a_1 pkgs/main
pyinstaller 3.4 py36h2a8f88b_1 pkgs/main
pyinstaller 3.4 py37h2a8f88b_1 pkgs/main
pyinstaller 3.5 py27h7a46e7a_0 pkgs/main
pyinstaller 3.5 py36h2a8f88b_0 pkgs/main
pyinstaller 3.5 py37h2a8f88b_0 pkgs/main
pyinstaller 3.6 py36h2a8f88b_1 pkgs/main
pyinstaller 3.6 py36h2a8f88b_2 pkgs/main
pyinstaller 3.6 py36h62dcd97_4 pkgs/main
pyinstaller 3.6 py36h62dcd97_5 pkgs/main
pyinstaller 3.6 py37h2a8f88b_1 pkgs/main
pyinstaller 3.6 py37h2a8f88b_2 pkgs/main
pyinstaller 3.6 py37h62dcd97_4 pkgs/main
pyinstaller 3.6 py37h62dcd97_5 pkgs/main
pyinstaller 3.6 py38h2a8f88b_1 pkgs/main
pyinstaller 3.6 py38h2a8f88b_2 pkgs/main
pyinstaller 3.6 py38h62dcd97_4 pkgs/main
pyinstaller 3.6 py38h62dcd97_5 pkgs/main
(base) C:\work>
そう、他の、py2exe、cx_Freeze(cx-Freeze)、pyoxidizer、bbFreeze、py2app、Shiv、PyRun、pynsist、は、ことごとくダメだったのですよねぇ。ま、condaのオプションを変更して登録先を変更すれば見つけられそうでしたけど、デフォルトで入っていない、ということはちょっぴり信頼性が足りないのかな、という理由で候補から外すことにしました。いろいろとウロウロしている中で、Nuitka、Bazelというのはconda searchコマンドで見つけることができたのですけど、あんまりメジャーじゃなさそう、ということで、今回はパスすることにしました。はい、ぜんぜん検証まではしていませんので、ご了承くださいね。
(base) C:\work>conda search py2exe
Loading channels: done
No match found for: py2exe. Search: *py2exe*
PackagesNotFoundError: The following packages are not available from current channels:
- py2exe
Current channels:
- https://repo.anaconda.com/pkgs/main/win-64
- https://repo.anaconda.com/pkgs/main/noarch
- https://repo.anaconda.com/pkgs/r/win-64
- https://repo.anaconda.com/pkgs/r/noarch
- https://repo.anaconda.com/pkgs/msys2/win-64
- https://repo.anaconda.com/pkgs/msys2/noarch
To search for alternate channels that may provide the conda package you're
looking for, navigate to
https://anaconda.org
and use the search bar at the top of the page.
(base) C:\work>
セットアップ
早速ですが、PyInstallerをセットアップしていきます。公式ホームページ には、以下のコマンドでインストールできる、と書いてありました。
pip install pyinstaller
が、ぼくの使用している環境はAnaconda3ですので、condaを使ってセットアップします。コマンドは以下の通りです。
conda install pyinstaller
condaも調べていくと「-c」オプションでチャンネルを追加すれば、いろんなところからインストールできることがわかりました。conda-forgeチャンネルを指定すればもう少し新しいPyInstallerがインストールできることも分かったのですが、ここはあえてシンプルなやり方を使うことにしました。(condaにはconfigコマンドもあって、どのチャンネルからインストールするかの設定も変えられるのですね。)
(base) C:\work>conda install pyinstaller
Collecting package metadata (repodata.json): done
Solving environment: done
## Package Plan ##
environment location: C:\ProgramData\Anaconda3
added / updated specs:
- pyinstaller
The following packages will be downloaded:
package | build
---------------------------|-----------------
altgraph-0.17 | py_0 21 KB
ca-certificates-2020.10.14 | 0 159 KB
certifi-2020.6.20 | pyhd3eb1b0_3 159 KB
conda-4.9.2 | py37haa95532_0 3.1 MB
macholib-1.14 | py_1 36 KB
openssl-1.1.1c | he774522_1 5.7 MB
pefile-2019.4.18 | py_0 54 KB
pycryptodome-3.7.3 | py37he774522_0 5.9 MB
pyinstaller-3.6 | py37h62dcd97_5 2.4 MB
pywin32-ctypes-0.2.0 | py37_1001 38 KB
------------------------------------------------------------
Total: 17.7 MB
The following NEW packages will be INSTALLED:
altgraph pkgs/main/noarch::altgraph-0.17-py_0
macholib pkgs/main/noarch::macholib-1.14-py_1
pefile pkgs/main/noarch::pefile-2019.4.18-py_0
pycryptodome pkgs/main/win-64::pycryptodome-3.7.3-py37he774522_0
pyinstaller pkgs/main/win-64::pyinstaller-3.6-py37h62dcd97_5
pywin32-ctypes pkgs/main/win-64::pywin32-ctypes-0.2.0-py37_1001
The following packages will be UPDATED:
ca-certificates anaconda::ca-certificates-2020.1.1-0 --> pkgs/main::ca-certificates-2020.10.14-0
certifi anaconda/win-64::certifi-2019.11.28-p~ --> pkgs/main/noarch::certifi-2020.6.20-pyhd3eb1b0_3
conda anaconda::conda-4.8.3-py37_0 --> pkgs/main::conda-4.9.2-py37haa95532_0
The following packages will be SUPERSEDED by a higher-priority channel:
openssl anaconda::openssl-1.1.1-he774522_0 --> pkgs/main::openssl-1.1.1c-he774522_1
Proceed ([y]/n)?
と、いうことでセットアップ完了です。あ、、、完了してませんでした。「y」を押して、エンターキーで続行します。
Proceed ([y]/n)? y
Downloading and Extracting Packages
macholib-1.14 | 36 KB | ########################################### | 100%
pywin32-ctypes-0.2.0 | 38 KB | ########################################### | 100%
ca-certificates-2020 | 159 KB | ########################################### | 100%
pyinstaller-3.6 | 2.4 MB | ########################################### | 100%
conda-4.9.2 | 3.1 MB | ########################################### | 100%
openssl-1.1.1c | 5.7 MB | ########################################### | 100%
pycryptodome-3.7.3 | 5.9 MB | ########################################### | 100%
pefile-2019.4.18 | 54 KB | ########################################### | 100%
certifi-2020.6.20 | 159 KB | ########################################### | 100%
altgraph-0.17 | 21 KB | ########################################### | 100%
Preparing transaction: done
Verifying transaction: failed
EnvironmentNotWritableError: The current user does not have write permissions to the target environment.
environment location: C:\ProgramData\Anaconda3
(base) C:\work>
ということで今度こそ、完了、、、と、思いましが「EnvironmentNotWritableError」が出ていました。これは、Anaconda3を実行したユーザーに権限がなくて、書き込めていない、ということのようです。ということで、気を取り直して、Anaconda Promptを管理者権限で実行して、再度やり直しです。ダウンロードまでは済んでいたので、スキップされました。もう一度Proceed ([y]/n)? で「y」を入力すると、4~5行ほど何かが表示された後クリアされ、
done
(base) C:\work>
と出力されました。「done」だから、完了、ですよね?
お試し
では、さっそくお試しです。お試しコマンドは公式ホームページの下の方に ありました。
pyinstaller yourprogram.py
前回つくったスクリプト「connecter_test3.py」でお試ししてみました。実行結果は以下の通りですね。
(base) C:\work\tkinter_example>pyinstaller connecter_test3.py
61 INFO: PyInstaller: 3.6
62 INFO: Python: 3.7.3 (conda)
64 INFO: Platform: Windows-10-10.0.18362-SP0
65 INFO: wrote C:\work\tkinter_example\connecter_test3.spec
68 INFO: UPX is not available.
70 INFO: Extending PYTHONPATH with paths
['C:\\work\\tkinter_example', 'C:\\work\\tkinter_example']
70 INFO: checking Analysis
71 INFO: Building Analysis because Analysis-00.toc is non existent
72 INFO: Initializing module dependency graph...
84 INFO: Caching module graph hooks...
96 INFO: Analyzing base_library.zip ...
5632 INFO: Caching module dependency graph...
5744 INFO: running Analysis Analysis-00.toc
5769 INFO: Adding Microsoft.Windows.Common-Controls to dependent assemblies of final executable
required by C:\ProgramData\Anaconda3\python.exe
6120 INFO: Analyzing C:\work\tkinter_example\connecter_test3.py
6308 INFO: Processing module hooks...
6309 INFO: Loading module hook "hook-encodings.py"...
6411 INFO: Loading module hook "hook-pydoc.py"...
6413 INFO: Loading module hook "hook-xml.py"...
6886 INFO: Loading module hook "hook-_tkinter.py"...
7253 INFO: checking Tree
7253 INFO: Building Tree because Tree-00.toc is non existent
7259 INFO: Building Tree Tree-00.toc
7355 INFO: checking Tree
7356 INFO: Building Tree because Tree-01.toc is non existent
7357 INFO: Building Tree Tree-01.toc
7396 INFO: Looking for ctypes DLLs
7418 INFO: Analyzing run-time hooks ...
7423 INFO: Including run-time hook 'pyi_rth__tkinter.py'
7429 INFO: Looking for dynamic libraries
7698 INFO: Looking for eggs
7699 INFO: Using Python library C:\ProgramData\Anaconda3\python37.dll
7700 INFO: Found binding redirects:
[]
7703 INFO: Warnings written to C:\work\tkinter_example\build\connecter_test3\warn-connecter_test3.txt
7742 INFO: Graph cross-reference written to C:\work\tkinter_example\build\connecter_test3\xref-connecter_test3.html
7784 INFO: checking PYZ
7784 INFO: Building PYZ because PYZ-00.toc is non existent
7786 INFO: Building PYZ (ZlibArchive) C:\work\tkinter_example\build\connecter_test3\PYZ-00.pyz
8370 INFO: Building PYZ (ZlibArchive) C:\work\tkinter_example\build\connecter_test3\PYZ-00.pyz completed successfully.
8378 INFO: checking PKG
8379 INFO: Building PKG because PKG-00.toc is non existent
8379 INFO: Building PKG (CArchive) PKG-00.pkg
8398 INFO: Building PKG (CArchive) PKG-00.pkg completed successfully.
8400 INFO: Bootloader C:\ProgramData\Anaconda3\lib\site-packages\PyInstaller\bootloader\Windows-64bit\run.exe
8400 INFO: checking EXE
8401 INFO: Building EXE because EXE-00.toc is non existent
8401 INFO: Building EXE from EXE-00.toc
8402 INFO: Appending archive to EXE C:\work\tkinter_example\build\connecter_test3\connecter_test3.exe
8406 INFO: Building EXE from EXE-00.toc completed successfully.
8410 INFO: checking COLLECT
8411 INFO: Building COLLECT because COLLECT-00.toc is non existent
8412 INFO: Building COLLECT COLLECT-00.toc
10094 INFO: Building COLLECT COLLECT-00.toc completed successfully.
(base) C:\work\tkinter_example>
配下に「build」「dist」サブフォルダができていました。本家のページに 書いてありましたが「dist」というサブディレクトリにバンドルが生成される、ということですので「dist」の方が最終的な出力先なのでしょう。両方のディレクトリに「connecter_test3.exe」が生成されていましたので、実行してみました。「dist」は動きましたが、「build」は動きませんでした。ただ、「dist」の動作結果も以下の通り、コマンドプロンプトのウィンドウが余分に表示されていましたので、GUIプログラムのバンドルを生成する場合は、オプションでなんとかしなければいけません。
distへできあがったconnecter_test3.exeをエクスプローラからダブルクリックで実行したところ。
ちなみに、「build」の方ですが、コマンドプロンプトから実行して確認してみたところ、メッセージが出力されていました。
(base) C:\work\tkinter_example\build\connecter_test3>connecter_test3.exe
Error loading Python DLL 'C:\work\tkinter_example\build\connecter_test3\python37.dll'.
LoadLibrary: 指定されたモジュールが見つかりません。
(base) C:\work\tkinter_example\build\connecter_test3>
「dist」のディレクトリには「python37.dll」がありましたので、「build」は途中生成物か、実行環境上での共通ではない変更されるもの、ということなのかな?
そういえば、色々見ている中で、PyInstallerには、–onefileオプションがあったなぁ、ということで使い方 を見てみました。で、出力される実行ファイルを一つに、コンソールなしで、というコマンドは以下の通りでした。
pyinstaller --onefile --windowed connecter_test3.py
実行結果は以下の通りです。
(base) C:\work\tkinter_example>pyinstaller --onefile --windowed connecter_test3.py
79 INFO: PyInstaller: 3.6
80 INFO: Python: 3.7.3 (conda)
81 INFO: Platform: Windows-10-10.0.18362-SP0
82 INFO: wrote C:\work\tkinter_example\connecter_test3.spec
85 INFO: UPX is not available.
86 INFO: Extending PYTHONPATH with paths
['C:\\work\\tkinter_example', 'C:\\work\\tkinter_example']
86 INFO: checking Analysis
160 INFO: checking PYZ
182 INFO: checking PKG
235 INFO: Building because C:\work\tkinter_example\build\connecter_test3\connecter_test3.exe.manifest changed
235 INFO: Building PKG (CArchive) PKG-00.pkg
2640 INFO: Building PKG (CArchive) PKG-00.pkg completed successfully.
2663 INFO: Bootloader C:\ProgramData\Anaconda3\lib\site-packages\PyInstaller\bootloader\Windows-64bit\runw.exe
2663 INFO: checking EXE
2673 INFO: Building because console changed
2673 INFO: Building EXE from EXE-00.toc
2676 INFO: Appending archive to EXE C:\work\tkinter_example\dist\connecter_test3.exe
2686 INFO: Building EXE from EXE-00.toc completed successfully.
(base) C:\work\tkinter_example>
実行したら、引数の.pyファイルを分析して、.specファイルができるとのこと。おお、確かに、できてました。
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['connecter_test3.py'],
pathex=['C:\\work\\tkinter_example'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='connecter_test3',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False )
specファイルは、pyinstallerコマンドに指定して実行することができるファイルで、コマンドラインで指定したオプションのかわりになるファイルです。specファイルの書き方の詳細は、ここ にありました。まずは、コマンドラインで実行してspecファイルを生成してから、以降はこのspecファイルで生成するのがよいでしょうか。
まとめ
いろいろと実験してみましたが、アイコンファイルや画像ファイル等の別ファイルを使うとコマンドラインオプションでいろいろと指定する必要が出てきそうです。そんなときは、コマンドラインの指定をバッチスクリプトにしておくか、specファイルを利用する、というのが推奨されたやり方のようです。