今日も見に来てくださって、ありがとうございます。石川さんです。
今回は、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プログラムのバンドルを生成する場合は、オプションでなんとかしなければいけません。
ちなみに、「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ファイルを利用する、というのが推奨されたやり方のようです。