「Pythonその他 - 実行ファイル」の版間の差分
ページの作成:「== 概要 == Pythonプロジェクトを実行ファイルに変換する手順を記載する。<br> <br><br> == 実行ファイルの作成 == Pythonプロジェクト…」 |
編集の要約なし |
||
| 1行目: | 1行目: | ||
== 概要 == | == 概要 == | ||
Pythonスクリプトを実行ファイル化することにより、Pythonがインストールされていない環境でもプログラムを実行できるようになる。<br> | |||
実行ファイル化のツールとして広く使用されており信頼性の高いPyInstallerやNuitkaが存在する。<br> | |||
<br> | |||
PyInstallerの主な特徴を以下に示す。<br> | |||
* 単一ファイルまたはフォルダ形式での出力 | |||
* Windows、Linux、MacOSに対応 | |||
* 依存モジュールの自動検出 | |||
* データファイルやリソースの組み込み | |||
* GUIアプリケーションのサポート | |||
<br><br> | <br><br> | ||
== | == 複数ファイルで構成されるプロジェクトの構造 == | ||
実際の開発では、単一ファイルではなく複数のモジュールに分割されたプロジェクト構造が一般的である。<br> | |||
<br> | <br> | ||
==== 想定するプロジェクト構造 ==== | |||
この構造において、<u>main.py</u> ファイルがエントリーポイントとなり、他のモジュールをimportして使用する。<br> | |||
<br> | |||
my_project/ | |||
├── main.py # エントリーポイント (メインスクリプト) | |||
├── requirements.txt # 依存パッケージ一覧 | |||
├── config.ini # 設定ファイル (データファイル) | |||
├── resources/ # リソースフォルダ | |||
│ ├── images/ | |||
│ │ └── logo.png | |||
│ └── data/ | |||
│ └── default_settings.json | |||
├── src/ # ソースコードのメインパッケージ | |||
│ ├── __init__.py | |||
│ ├── core/ # コア機能モジュール | |||
│ │ ├── __init__.py | |||
│ │ ├── engine.py | |||
│ │ └── processor.py | |||
│ ├── ui/ # UI関連モジュール | |||
│ │ ├── __init__.py | |||
│ │ ├── main_window.py | |||
│ │ └── dialogs.py | |||
│ └── utils/ # ユーティリティモジュール | |||
│ ├── __init__.py | |||
│ ├── file_handler.py | |||
│ └── logger.py | |||
└── tests/ # テストコード (実行ファイルには含めない) | |||
├── __init__.py | |||
└── test_engine.py | |||
<br> | |||
==== エントリーポイント (main.py) の例 ==== | |||
<syntaxhighlight lang="python"> | |||
#!/usr/bin/env python3 | |||
# -*- coding: utf-8 -*- | |||
""" | |||
アプリケーションのエントリーポイント | |||
PyInstallerでexe化する際は、このファイルを指定する | |||
""" | |||
import sys | |||
import os | |||
def get_base_path(): | |||
""" | |||
実行ファイルのベースパスを取得する。 | |||
PyInstallerでパッケージ化された場合と、通常のPython実行の場合で | |||
パスの取得方法が異なるため、この関数で吸収する。 | |||
""" | |||
if getattr(sys, 'frozen', False): | |||
# PyInstallerで実行されている場合 | |||
# sys._MEIPASS は一時展開フォルダのパス (--onefileの場合) | |||
# sys.executable は実行ファイル自体のパス | |||
return os.path.dirname(sys.executable) | |||
else: | |||
# 通常のPython実行の場合 | |||
return os.path.dirname(os.path.abspath(__file__)) | |||
def get_resource_path(relative_path): | |||
""" | |||
リソースファイルへのパスを取得する。 | |||
--add-data で含めたファイルにアクセスする際に使用する。 | |||
""" | |||
if getattr(sys, 'frozen', False): | |||
# PyInstallerの一時展開フォルダ内のパス | |||
base_path = sys._MEIPASS | |||
else: | |||
base_path = os.path.dirname(os.path.abspath(__file__)) | |||
return os.path.join(base_path, relative_path) | |||
def main(): | |||
"""メイン関数""" | |||
# リソースファイルへのアクセス例 | |||
config_path = get_resource_path('config.ini') | |||
logo_path = get_resource_path(os.path.join('resources', 'images', 'logo.png')) | |||
# 各モジュールのimport | |||
from src.core.engine import Engine | |||
from src.ui.main_window import MainWindow | |||
from src.utils.logger import setup_logging | |||
# ロギングの設定 | |||
setup_logging() | |||
# アプリケーションの起動 | |||
engine = Engine() | |||
window = MainWindow(engine) | |||
window.run() | |||
if __name__ == '__main__': | |||
main() | |||
</syntaxhighlight> | |||
<br><br> | |||
== Windows == | |||
==== 環境構築 ==== | |||
コマンドプロンプトまたはPowerShellを開き、Pythonのバージョンを確認する。<br> | |||
python --version | |||
pip --version | |||
<br> | |||
<code>python</code> コマンドが認識されない場合は、Pythonのインストール時に[Add Python to PATH]にチェックを入力し忘れている可能性がある。<br> | |||
その場合は環境変数を手動で設定、または、Pythonを再インストールする。<br> | |||
<br> | |||
==== 仮想環境の作成 ==== | |||
プロジェクトフォルダに移動して仮想環境を作成する。<br> | |||
仮想環境を使用することで、実行ファイルに不要なパッケージが含まれることを防ぎ、ファイルサイズを最小限に抑えられる。<br> | |||
cd C:\path\to\my_project | |||
python -m venv venv | |||
venv\Scripts\activate | |||
<br> | |||
プロンプトの先頭に <u>(venv)</u> と表示されれば、仮想環境がアクティブになっている。<br> | |||
<br> | |||
==== 依存パッケージとPyInstallerのインストール ==== | |||
pip install pyinstaller | pip install pyinstaller | ||
pip install -r requirements.txt | |||
<br> | <br> | ||
==== 基本的なビルドコマンド ==== | |||
複数ファイルのプロジェクトでも、指定するのはエントリーポイントのファイルだけである。<br> | |||
PyInstallerは、そのファイルからimportされている全てのモジュールを自動的に追跡して、実行ファイルに含める。<br> | |||
pyinstaller main.py | |||
pyinstaller | |||
<br> | <br> | ||
このコマンドにより、<u>main.py</u> がimportしている <u>src.core.engine</u>、<u>src.ui.main_window</u> 等のモジュールは自動的に検出されて、実行ファイルに組み込まれる。<br> | |||
<br> | <br> | ||
<u> | ==== 生成されるディレクトリとファイル ==== | ||
<center> | |||
{| class="wikitable" | |||
|+ ビルド時に生成されるディレクトリとファイル | |||
|- | |||
! ディレクトリ / ファイル !! 説明 | |||
|- | |||
| build/ || PyInstallerが作業中に使用する一時ファイルの格納場所。<br>配布時には不要。 | |||
|- | |||
| dist/ || 生成された実行ファイルと依存ファイルの格納場所。 | |||
|- | |||
| your_script.spec || PyInstallerの設定ファイル。<br>カスタマイズに使用する。 | |||
|} | |||
</center> | |||
<br> | |||
==== データファイルとリソースの追加 ==== | |||
Pythonソースコード以外のファイル (設定ファイル、画像、JSONデータ等) は自動的には含まれない。<br> | |||
<code>--add-data</code> オプションで明示的に指定する必要がある。<br> | |||
pyinstaller --onefile ^ | |||
--add-data "config.ini;." ^ | |||
--add-data "resources;resources" ^ | |||
main.py | |||
<br> | |||
<code>--add-data</code> オプションの書式は、<code>"元のパス;実行ファイル内での配置先パス"</code>となる。<br> | |||
Windowsではセミコロン (<code>;</code>) を区切り文字として使用する。<br> | |||
<br> | |||
上記の例では、config.iniファイルは実行ファイルと同じ階層に配置され、resourcesフォルダはその中身ごとresourcesという名前で配置される。<br> | |||
<br> | |||
==== GUIアプリケーション向けオプション ==== | |||
GUIアプリケーションの場合は、コンソールウィンドウを非表示にし、アイコンを設定する。<br> | |||
pyinstaller --onefile --noconsole ^ | |||
--icon=resources\images\app_icon.ico ^ | |||
--name=MyApplication ^ | |||
--add-data "config.ini;." ^ | |||
--add-data "resources;resources" ^ | |||
main.py | |||
<br> | |||
<center> | |||
{| class="wikitable" | |||
|+ 主なオプション | |||
|- | |||
! オプション !! 説明 | |||
|- | |||
| --onefile || 単一の実行ファイルにまとめる | |||
|- | |||
| --noconsole || コンソールウィンドウを非表示 (GUIアプリ向け) | |||
|- | |||
| --windowed || --noconsoleと同じ | |||
|- | |||
| --icon || アイコンファイルを指定 (.ico形式) | |||
|- | |||
| --name || 出力ファイル名を指定 | |||
|- | |||
| --add-data || データファイルを追加 | |||
|- | |||
| --hidden-import || 自動検出されないモジュールを追加 | |||
|} | |||
</center> | |||
<br> | |||
==== specファイルを使用した詳細設定 ==== | |||
複雑なプロジェクトでは、specファイルを使用して設定を管理することを推奨する。<br> | |||
まず、初回のビルドでspecファイルを生成する。<br> | |||
pyinstaller --onefile --noconsole --name=MyApplication main.py | |||
<br> | |||
生成されたMyApplication.specファイルを開いて、必要に応じて編集する。<br> | |||
<syntaxhighlight lang="python"> | |||
# -*- mode: python ; coding: utf-8 -*- | |||
block_cipher = None | |||
# データファイルの定義 | |||
# 形式: (元のパス, 実行ファイル内での配置先) | |||
added_files = [ | |||
('config.ini', '.'), | |||
('resources/images', 'resources/images'), | |||
('resources/data', 'resources/data'), | |||
] | |||
# 自動検出されないモジュールがある場合に追加 | |||
hidden_imports = [ | |||
# 例: 動的インポートを使用している場合 | |||
# 'src.plugins.optional_module', | |||
] | |||
# 除外するモジュール (ファイルサイズ削減のため) | |||
excludes = [ | |||
'tkinter', # GUIフレームワークを使わない場合 | |||
'unittest', # テストフレームワーク | |||
'pytest', | |||
] | |||
a = Analysis( | |||
['main.py'], | |||
pathex=[], | |||
binaries=[], | |||
datas=added_files, | |||
hiddenimports=hidden_imports, | |||
hookspath=[], | |||
hooksconfig={}, | |||
runtime_hooks=[], | |||
excludes=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.datas, | |||
[], | |||
name='MyApplication', | |||
debug=False, | |||
bootloader_ignore_signals=False, | |||
strip=False, | |||
upx=True, # UPX圧縮を使用 (インストール済みの場合) | |||
upx_exclude=[], | |||
runtime_tmpdir=None, | |||
console=False, # コンソールウィンドウを非表示 | |||
disable_windowed_traceback=False, | |||
argv_emulation=False, | |||
target_arch=None, | |||
codesign_identity=None, | |||
entitlements_file=None, | |||
icon='resources\\images\\app_icon.ico', | |||
) | |||
</syntaxhighlight> | |||
<br> | |||
specファイルを編集した後は、以下に示すコマンドを実行してビルドする。<br> | |||
pyinstaller MyApplication.spec | |||
<br> | |||
==== Hidden Importsの対処 ==== | |||
PyInstallerは静的解析によってimportを検出するが、以下のようなケースでは自動検出できないことがある。<br> | |||
<br> | |||
* 動的インポートを使用している場合 | |||
*: <code>importlib.import_module()</code> 等 | |||
* 文字列からモジュールを参照している場合 | |||
* 一部の複雑なライブラリ | |||
*: pandas、scipy、scikit-learn、PIL等のサブモジュール | |||
<br> | |||
エラーメッセージに <u>ModuleNotFoundError</u> が含まれている場合は、そのモジュールを <code>--hidden-import</code> オプションで追加する。<br> | |||
pyinstaller --onefile --hidden-import=PIL._tkinter_finder main.py | |||
<br> | |||
または、specファイルの <u>hiddenimports</u> リストに追加する。<br> | |||
<br> | |||
==== Windows用ビルドスクリプト ==== | |||
ビルド作業を効率化するため、バッチファイルを作成することを推奨する。<br> | |||
<syntaxhighlight lang="batch"> | |||
@echo off | |||
setlocal | |||
REM 仮想環境のアクティベート | |||
call venv\Scripts\activate | |||
REM 出力ディレクトリの作成 | |||
if not exist dist\windows mkdir dist\windows | |||
REM PyInstallerの実行 | |||
pyinstaller --onefile --noconsole ^ | |||
--distpath dist\windows ^ | |||
--workpath build\windows ^ | |||
--add-data "config.ini;." ^ | |||
--add-data "resources;resources" ^ | |||
--icon=resources\images\app_icon.ico ^ | |||
--name=MyApplication ^ | |||
main.py | |||
echo. | |||
echo ビルドが完了しました。出力先: dist\windows\MyApplication.exe | |||
pause | |||
</syntaxhighlight> | |||
<br><br> | <br><br> | ||
== RHEL / SUSE == | |||
==== 前提条件 ==== | |||
PyInstallerはクロスコンパイルをサポートしていない。<br> | |||
Linux向けの実行ファイルを作成するには、Linux環境でPyInstallerを実行する必要がある。<br> | |||
<br> | |||
もし、Windows環境からLinux向けの実行ファイルを作成する場合は、WSL2、Docker、仮想マシンを使用する。<br> | |||
<br> | |||
==== 環境構築 ==== | |||
===== RHEL ===== | |||
まず、Pythonと開発ツールをインストールする。<br> | |||
# RHEL | |||
sudo dnf install python3 python3-pip python3-devel | |||
sudo dnf groupinstall "Development Tools" | |||
<br> | |||
RHELでは、デフォルトのPythonバージョンがシステムによって異なる。<br> | |||
例えば、Python 3.9以上を使用する場合は、以下に示すようにインストールする。<br> | |||
# Python 3.11を使用する場合 | |||
sudo dnf install python3.11 python3.11-pip python3.11-devel | |||
<br> | |||
===== SUSE ===== | |||
まず、Pythonと開発ツールをインストールする。<br> | |||
devel_basisパターンには、gcc、make等の基本的な開発ツールが含まれている。<br> | |||
<br> | |||
# SUSE | |||
sudo zypper install -t pattern devel_basis | |||
sudo zypper install python3 python3-pip python3-devel | |||
<br> | |||
==== 仮想環境の作成 ==== | |||
プロジェクトディレクトリに移動して、仮想環境を作成する。<br> | |||
cd /path/to/my_project | |||
python3 -m venv venv | |||
source venv/bin/activate | |||
<br> | |||
特定バージョンのPythonを使用する場合は、そのバージョンを明示的に指定する。<br> | |||
python3.11 -m venv venv | |||
source venv/bin/activate | |||
<br> | |||
==== 依存パッケージとPyInstallerのインストール ==== | |||
pip install --upgrade pip | |||
pip install pyinstaller | |||
pip install -r requirements.txt | |||
<br> | |||
==== 実行ファイルの作成 ==== | |||
基本的なコマンド構文はWindowsと同様である、<code>--add-data</code> オプションの区切り文字がコロン (<code>:</code>) になることに注意する。<br> | |||
pyinstaller --onefile \ | |||
--add-data "config.ini:." \ | |||
--add-data "resources:resources" \ | |||
main.py | |||
<br> | |||
GUIアプリケーションの場合は、X11環境が必要となる。<br> | |||
pyinstaller --onefile --noconsole \ | |||
--add-data "config.ini:." \ | |||
--add-data "resources:resources" \ | |||
--name=MyApplication \ | |||
main.py | |||
<br> | |||
==== specファイルを使用した設定 ==== | |||
Linuxでのspecファイルは、パス区切り文字がスラッシュになる点を除き、Windowsとほぼ同じ構造である。<br> | |||
<syntaxhighlight lang="python"> | |||
# -*- mode: python ; coding: utf-8 -*- | |||
block_cipher = None | |||
# データファイルの定義 (Linux版) | |||
# パス区切り文字は / を使用 | |||
added_files = [ | |||
('config.ini', '.'), | |||
('resources/images', 'resources/images'), | |||
('resources/data', 'resources/data'), | |||
] | |||
hidden_imports = [] | |||
excludes = [ | |||
'tkinter', | |||
'unittest', | |||
'pytest', | |||
] | |||
a = Analysis( | |||
['main.py'], | |||
pathex=[], | |||
binaries=[], | |||
datas=added_files, | |||
hiddenimports=hidden_imports, | |||
hookspath=[], | |||
hooksconfig={}, | |||
runtime_hooks=[], | |||
excludes=excludes, | |||
noarchive=False, | |||
) | |||
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) | |||
exe = EXE( | |||
pyz, | |||
a.scripts, | |||
a.binaries, | |||
a.datas, | |||
[], | |||
name='MyApplication', | |||
debug=False, | |||
bootloader_ignore_signals=False, | |||
strip=False, | |||
upx=True, | |||
upx_exclude=[], | |||
runtime_tmpdir=None, | |||
console=True, # CLIアプリの場合はTrue、GUIの場合はFalse | |||
) | |||
</syntaxhighlight> | |||
<br> | |||
==== 実行権限の付加と動作確認 ==== | |||
# 実行権限の付加 | |||
ls -la dist/MyApplication | |||
chmod u+x dist/MyApplication # 必要な場合 | |||
# 動作確認 | |||
./dist/MyApplication | |||
<br> | |||
==== GLIBCバージョンの互換性について ==== | |||
PyInstallerで生成されたバイナリは、ビルド環境のGLIBCバージョンに依存する。<br> | |||
新しいGLIBCでビルドしたバイナリは、古いGLIBCを持つシステムでは動作しない可能性がある。<br> | |||
<br> | |||
配布先の環境で確実に動作させるためには、以下に示す事柄を考慮する。<br> | |||
* ターゲット環境と同じ、あるいは、それより古いバージョンのディストリビューションんでビルドする。 | |||
*: 例 : RHEL 9向けの実行ファイルを作成する場合は、RHEL 9環境でビルドする。 | |||
<br> | |||
現在のGLIBCバージョンは以下に示すコマンドで確認できる。<br> | |||
ldd --version | |||
# または | |||
rpm -q glibc | |||
<br> | |||
==== 共有ライブラリの依存関係の確認 ==== | |||
生成されたバイナリが依存している共有ライブラリを確認するには、<code>ldd</code> コマンドを使用する。<br> | |||
ldd dist/MyApplication | |||
<br> | |||
<u>"not found:</u> と表示されるライブラリがある場合、そのバイナリはターゲット環境で動作しない可能性がある。<br> | |||
<br> | |||
==== Linux向けビルドスクリプト ==== | |||
<syntaxhighlight lang="bash"> | |||
#!/usr/bin/env sh | |||
# 仮想環境のアクティベート | |||
source venv/bin/activate | |||
# 出力ディレクトリの作成 | |||
mkdir -p dist/linux | |||
# PyInstallerの実行 | |||
pyinstaller --onefile \ | |||
--distpath dist/linux \ | |||
--workpath build/linux \ | |||
--add-data "config.ini:." \ | |||
--add-data "resources:resources" \ | |||
--name=MyApplication \ | |||
main.py | |||
echo "" | |||
echo "ビルドが完了しました。出力先: dist/linux/MyApplication" | |||
</syntaxhighlight> | |||
<br> | |||
スクリプトに実行権限を付与する。<br> | |||
chmod u+x build_scripts/build_linux.sh | |||
<br><br> | |||
== Nuitkaを使用した高度なコンパイル == | |||
Nuitkaは、PythonコードをC言語にコンパイルしてから実行ファイルを生成するツールである。<br> | |||
PyInstallerと比較して、実行速度が向上し、リバースエンジニアリングへの耐性も高くなる。<br> | |||
<br> | |||
==== Nuitkaのインストール ==== | |||
pip install nuitka | |||
<br> | |||
Windows環境では、Visual Studio Build Tools または MinGW-w64 が必要である。<br> | |||
Linux環境では、GCCと関連ツールが必要である。<br> | |||
# RHEL | |||
sudo dnf install gcc gcc-c++ | |||
# SUSE | |||
sudo zypper install gcc gcc-c++ | |||
<br> | |||
==== 基本的な使用方法 ==== | |||
# CLIアプリケーションの場合 | |||
python -m nuitka --standalone --onefile your_script.py | |||
# GUIアプリケーションの場合 | |||
python -m nuitka --standalone --onefile --windows-disable-console --windows-icon-from-ico=icon.ico your_script.py | |||
<br> | |||
Nuitkaは初回ビルド時に時間が掛かるが、生成される実行ファイルは一般的にPyInstallerよりも高速に動作する。<br> | |||
<br><br> | |||
== トラブルシューティング == | |||
==== ModuleNotFoundErrorが発生する ==== | |||
* 原因 | |||
*: PyInstallerが動的インポートや特定のライブラリのサブモジュールを検出できていない。 | |||
* 対処法 | |||
*: エラーメッセージに表示されているモジュールを <code>--hidden-import</code> オプションで追加する。 | |||
<br> | |||
pyinstaller --onefile --hidden-import=missing_module main.py | |||
<br> | |||
よく問題になるライブラリと対処例を以下に示す。<br> | |||
<center> | |||
{| class="wikitable" | |||
|+ Hidden Importが必要になることが多いライブラリ | |||
|- | |||
! ライブラリ !! 追加が必要なモジュールの例 | |||
|- | |||
| pandas || pandas._libs.tslibs.timedeltas | |||
|- | |||
| PIL / Pillow || PIL._tkinter_finder | |||
|- | |||
| scikit-learn || --collect-submodules=sklearn | |||
|} | |||
</center> | |||
<br> | |||
==== ファイルが見つからないエラー ==== | |||
* 原因 | |||
*: データファイル (設定ファイル、画像等) が実行ファイルに含まれていない、または、パスの解決が正しくない。 | |||
* 対処法 | |||
*: <code>--add-data</code> オプションでファイルを正しく含めているか確認する。 | |||
*: ソースコード内で <code>get_resource_path()</code> メソッドを使用してパスを解決しているかどうかを確認する。 | |||
<br> | |||
==== 実行ファイルのサイズが大きすぎる ==== | |||
対処法を以下に示す。<br> | |||
<br> | |||
* 仮想環境を使用して、必要なパッケージのみをインストールした環境でビルドする。 | |||
* specファイルの <u>excludes</u> リストに、使用していないモジュールを追加する。 | |||
* UPX圧縮を使用する。 | |||
*: もしUPXがインストールされていれば、PyInstallerは自動的に使用する。 | |||
*: <br> | |||
*: UPXのインストール手順を以下に示す。 | |||
*: <syntaxhighlight lang="text"> | |||
# RHEL | |||
sudo dnf install upx | |||
# SUSE | |||
sudo zypper install upx | |||
</syntaxhighlight> | |||
<br> | |||
==== "GLIBC_X.XX not found" エラー ==== | |||
* 原因 | |||
*: ビルド環境のGLIBCのバージョンが、実行環境より新しい。 | |||
* 対処法 | |||
*: ターゲット環境と同じか、それより古いバージョンのLinuxでビルドする。 | |||
*: Dockerを使用して古い環境でビルドする方法も効果的である。 | |||
*: <br> | |||
*: Dockerを使用したビルド方法を以下に示す。 | |||
*: <syntaxhighlight lang="text"> | |||
# 例: openSUSE Leap 15.1のDockerコンテナでビルド | |||
docker run -it -v $(pwd):/app opensuse/leap:15.1 bash | |||
# コンテナ内でPythonとPyInstallerをセットアップしてビルド | |||
# ...略 | |||
</syntaxhighlight> | |||
<br><br> | |||
== 手法の選択指針 == | |||
<center> | |||
{| class="wikitable" | |||
|+ ツール選択の指針 | |||
|- | |||
! 用途 !! 推奨ツール !! 備考 | |||
|- | |||
| 通常の用途で手軽に実行ファイルを作成したい || PyInstaller || 豊富な情報があり、トラブルシューティングも容易 | |||
|- | |||
| 実行速度を重視する || Nuitka || ビルド環境の準備とビルド時間が増加する | |||
|- | |||
| コードの難読化を強化したい || Nuitka || C言語へのコンパイルにより難読化される | |||
|- | |||
| クロスプラットフォーム対応が必要 || PyInstaller || 各OSの環境でそれぞれビルドを行う必要がある | |||
|} | |||
</center> | |||
<br> | |||
クロスプラットフォーム対応が必要な場合は、各OSの環境 (実機、VM、Docker、WSL2等) でそれぞれビルドを行う必要がある。<br> | |||
CI/CDパイプライン (GitHub Actions等) を活用すると、複数プラットフォーム向けのビルドを自動化できる。<br> | |||
<br><br> | |||
== 外部リンク == | |||
* [https://pyinstaller.org/en/stable/ PyInstaller公式ドキュメント] | |||
* [https://nuitka.net/ Nuitka公式サイト] | |||
* [https://github.com/pyinstaller/pyinstaller PyInstaller GitHub] | |||
<br><br> | |||
{{#seo: | |||
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki | |||
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Python,PyInstaller,Nuitka,exe,実行ファイル,Windows,Linux,RHEL,SUSE,openSUSE,パッケージング,配布,デプロイ | |||
|description={{PAGENAME}} - PythonスクリプトをWindows exeやLinux実行ファイルに変換する方法 | This page is {{PAGENAME}} in our wiki about Python packaging and deployment | |||
|image=/resources/assets/MochiuLogo_Single_Blue.png | |||
}} | |||
__FORCETOC__ | __FORCETOC__ | ||
[[カテゴリ:Python]] | [[カテゴリ:Python]] | ||
2026年1月28日 (水) 15:25時点における版
概要
Pythonスクリプトを実行ファイル化することにより、Pythonがインストールされていない環境でもプログラムを実行できるようになる。
実行ファイル化のツールとして広く使用されており信頼性の高いPyInstallerやNuitkaが存在する。
PyInstallerの主な特徴を以下に示す。
- 単一ファイルまたはフォルダ形式での出力
- Windows、Linux、MacOSに対応
- 依存モジュールの自動検出
- データファイルやリソースの組み込み
- GUIアプリケーションのサポート
複数ファイルで構成されるプロジェクトの構造
実際の開発では、単一ファイルではなく複数のモジュールに分割されたプロジェクト構造が一般的である。
想定するプロジェクト構造
この構造において、main.py ファイルがエントリーポイントとなり、他のモジュールをimportして使用する。
my_project/
├── main.py # エントリーポイント (メインスクリプト)
├── requirements.txt # 依存パッケージ一覧
├── config.ini # 設定ファイル (データファイル)
├── resources/ # リソースフォルダ
│ ├── images/
│ │ └── logo.png
│ └── data/
│ └── default_settings.json
├── src/ # ソースコードのメインパッケージ
│ ├── __init__.py
│ ├── core/ # コア機能モジュール
│ │ ├── __init__.py
│ │ ├── engine.py
│ │ └── processor.py
│ ├── ui/ # UI関連モジュール
│ │ ├── __init__.py
│ │ ├── main_window.py
│ │ └── dialogs.py
│ └── utils/ # ユーティリティモジュール
│ ├── __init__.py
│ ├── file_handler.py
│ └── logger.py
└── tests/ # テストコード (実行ファイルには含めない)
├── __init__.py
└── test_engine.py
エントリーポイント (main.py) の例
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
アプリケーションのエントリーポイント
PyInstallerでexe化する際は、このファイルを指定する
"""
import sys
import os
def get_base_path():
"""
実行ファイルのベースパスを取得する。
PyInstallerでパッケージ化された場合と、通常のPython実行の場合で
パスの取得方法が異なるため、この関数で吸収する。
"""
if getattr(sys, 'frozen', False):
# PyInstallerで実行されている場合
# sys._MEIPASS は一時展開フォルダのパス (--onefileの場合)
# sys.executable は実行ファイル自体のパス
return os.path.dirname(sys.executable)
else:
# 通常のPython実行の場合
return os.path.dirname(os.path.abspath(__file__))
def get_resource_path(relative_path):
"""
リソースファイルへのパスを取得する。
--add-data で含めたファイルにアクセスする際に使用する。
"""
if getattr(sys, 'frozen', False):
# PyInstallerの一時展開フォルダ内のパス
base_path = sys._MEIPASS
else:
base_path = os.path.dirname(os.path.abspath(__file__))
return os.path.join(base_path, relative_path)
def main():
"""メイン関数"""
# リソースファイルへのアクセス例
config_path = get_resource_path('config.ini')
logo_path = get_resource_path(os.path.join('resources', 'images', 'logo.png'))
# 各モジュールのimport
from src.core.engine import Engine
from src.ui.main_window import MainWindow
from src.utils.logger import setup_logging
# ロギングの設定
setup_logging()
# アプリケーションの起動
engine = Engine()
window = MainWindow(engine)
window.run()
if __name__ == '__main__':
main()
Windows
環境構築
コマンドプロンプトまたはPowerShellを開き、Pythonのバージョンを確認する。
python --version pip --version
python コマンドが認識されない場合は、Pythonのインストール時に[Add Python to PATH]にチェックを入力し忘れている可能性がある。
その場合は環境変数を手動で設定、または、Pythonを再インストールする。
仮想環境の作成
プロジェクトフォルダに移動して仮想環境を作成する。
仮想環境を使用することで、実行ファイルに不要なパッケージが含まれることを防ぎ、ファイルサイズを最小限に抑えられる。
cd C:\path\to\my_project python -m venv venv venv\Scripts\activate
プロンプトの先頭に (venv) と表示されれば、仮想環境がアクティブになっている。
依存パッケージとPyInstallerのインストール
pip install pyinstaller pip install -r requirements.txt
基本的なビルドコマンド
複数ファイルのプロジェクトでも、指定するのはエントリーポイントのファイルだけである。
PyInstallerは、そのファイルからimportされている全てのモジュールを自動的に追跡して、実行ファイルに含める。
pyinstaller main.py
このコマンドにより、main.py がimportしている src.core.engine、src.ui.main_window 等のモジュールは自動的に検出されて、実行ファイルに組み込まれる。
生成されるディレクトリとファイル
| ディレクトリ / ファイル | 説明 |
|---|---|
| build/ | PyInstallerが作業中に使用する一時ファイルの格納場所。 配布時には不要。 |
| dist/ | 生成された実行ファイルと依存ファイルの格納場所。 |
| your_script.spec | PyInstallerの設定ファイル。 カスタマイズに使用する。 |
データファイルとリソースの追加
Pythonソースコード以外のファイル (設定ファイル、画像、JSONデータ等) は自動的には含まれない。
--add-data オプションで明示的に指定する必要がある。
pyinstaller --onefile ^ --add-data "config.ini;." ^ --add-data "resources;resources" ^ main.py
--add-data オプションの書式は、"元のパス;実行ファイル内での配置先パス"となる。
Windowsではセミコロン (;) を区切り文字として使用する。
上記の例では、config.iniファイルは実行ファイルと同じ階層に配置され、resourcesフォルダはその中身ごとresourcesという名前で配置される。
GUIアプリケーション向けオプション
GUIアプリケーションの場合は、コンソールウィンドウを非表示にし、アイコンを設定する。
pyinstaller --onefile --noconsole ^ --icon=resources\images\app_icon.ico ^ --name=MyApplication ^ --add-data "config.ini;." ^ --add-data "resources;resources" ^ main.py
| オプション | 説明 |
|---|---|
| --onefile | 単一の実行ファイルにまとめる |
| --noconsole | コンソールウィンドウを非表示 (GUIアプリ向け) |
| --windowed | --noconsoleと同じ |
| --icon | アイコンファイルを指定 (.ico形式) |
| --name | 出力ファイル名を指定 |
| --add-data | データファイルを追加 |
| --hidden-import | 自動検出されないモジュールを追加 |
specファイルを使用した詳細設定
複雑なプロジェクトでは、specファイルを使用して設定を管理することを推奨する。
まず、初回のビルドでspecファイルを生成する。
pyinstaller --onefile --noconsole --name=MyApplication main.py
生成されたMyApplication.specファイルを開いて、必要に応じて編集する。
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
# データファイルの定義
# 形式: (元のパス, 実行ファイル内での配置先)
added_files = [
('config.ini', '.'),
('resources/images', 'resources/images'),
('resources/data', 'resources/data'),
]
# 自動検出されないモジュールがある場合に追加
hidden_imports = [
# 例: 動的インポートを使用している場合
# 'src.plugins.optional_module',
]
# 除外するモジュール (ファイルサイズ削減のため)
excludes = [
'tkinter', # GUIフレームワークを使わない場合
'unittest', # テストフレームワーク
'pytest',
]
a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=added_files,
hiddenimports=hidden_imports,
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=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.datas,
[],
name='MyApplication',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True, # UPX圧縮を使用 (インストール済みの場合)
upx_exclude=[],
runtime_tmpdir=None,
console=False, # コンソールウィンドウを非表示
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon='resources\\images\\app_icon.ico',
)
specファイルを編集した後は、以下に示すコマンドを実行してビルドする。
pyinstaller MyApplication.spec
Hidden Importsの対処
PyInstallerは静的解析によってimportを検出するが、以下のようなケースでは自動検出できないことがある。
- 動的インポートを使用している場合
importlib.import_module()等
- 文字列からモジュールを参照している場合
- 一部の複雑なライブラリ
- pandas、scipy、scikit-learn、PIL等のサブモジュール
エラーメッセージに ModuleNotFoundError が含まれている場合は、そのモジュールを --hidden-import オプションで追加する。
pyinstaller --onefile --hidden-import=PIL._tkinter_finder main.py
または、specファイルの hiddenimports リストに追加する。
Windows用ビルドスクリプト
ビルド作業を効率化するため、バッチファイルを作成することを推奨する。
@echo off
setlocal
REM 仮想環境のアクティベート
call venv\Scripts\activate
REM 出力ディレクトリの作成
if not exist dist\windows mkdir dist\windows
REM PyInstallerの実行
pyinstaller --onefile --noconsole ^
--distpath dist\windows ^
--workpath build\windows ^
--add-data "config.ini;." ^
--add-data "resources;resources" ^
--icon=resources\images\app_icon.ico ^
--name=MyApplication ^
main.py
echo.
echo ビルドが完了しました。出力先: dist\windows\MyApplication.exe
pause
RHEL / SUSE
前提条件
PyInstallerはクロスコンパイルをサポートしていない。
Linux向けの実行ファイルを作成するには、Linux環境でPyInstallerを実行する必要がある。
もし、Windows環境からLinux向けの実行ファイルを作成する場合は、WSL2、Docker、仮想マシンを使用する。
環境構築
RHEL
まず、Pythonと開発ツールをインストールする。
# RHEL sudo dnf install python3 python3-pip python3-devel sudo dnf groupinstall "Development Tools"
RHELでは、デフォルトのPythonバージョンがシステムによって異なる。
例えば、Python 3.9以上を使用する場合は、以下に示すようにインストールする。
# Python 3.11を使用する場合 sudo dnf install python3.11 python3.11-pip python3.11-devel
SUSE
まず、Pythonと開発ツールをインストールする。
devel_basisパターンには、gcc、make等の基本的な開発ツールが含まれている。
# SUSE sudo zypper install -t pattern devel_basis sudo zypper install python3 python3-pip python3-devel
仮想環境の作成
プロジェクトディレクトリに移動して、仮想環境を作成する。
cd /path/to/my_project python3 -m venv venv source venv/bin/activate
特定バージョンのPythonを使用する場合は、そのバージョンを明示的に指定する。
python3.11 -m venv venv source venv/bin/activate
依存パッケージとPyInstallerのインストール
pip install --upgrade pip pip install pyinstaller pip install -r requirements.txt
実行ファイルの作成
基本的なコマンド構文はWindowsと同様である、--add-data オプションの区切り文字がコロン (:) になることに注意する。
pyinstaller --onefile \ --add-data "config.ini:." \ --add-data "resources:resources" \ main.py
GUIアプリケーションの場合は、X11環境が必要となる。
pyinstaller --onefile --noconsole \ --add-data "config.ini:." \ --add-data "resources:resources" \ --name=MyApplication \ main.py
specファイルを使用した設定
Linuxでのspecファイルは、パス区切り文字がスラッシュになる点を除き、Windowsとほぼ同じ構造である。
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
# データファイルの定義 (Linux版)
# パス区切り文字は / を使用
added_files = [
('config.ini', '.'),
('resources/images', 'resources/images'),
('resources/data', 'resources/data'),
]
hidden_imports = []
excludes = [
'tkinter',
'unittest',
'pytest',
]
a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=added_files,
hiddenimports=hidden_imports,
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=excludes,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='MyApplication',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True, # CLIアプリの場合はTrue、GUIの場合はFalse
)
実行権限の付加と動作確認
# 実行権限の付加 ls -la dist/MyApplication chmod u+x dist/MyApplication # 必要な場合 # 動作確認 ./dist/MyApplication
GLIBCバージョンの互換性について
PyInstallerで生成されたバイナリは、ビルド環境のGLIBCバージョンに依存する。
新しいGLIBCでビルドしたバイナリは、古いGLIBCを持つシステムでは動作しない可能性がある。
配布先の環境で確実に動作させるためには、以下に示す事柄を考慮する。
- ターゲット環境と同じ、あるいは、それより古いバージョンのディストリビューションんでビルドする。
- 例 : RHEL 9向けの実行ファイルを作成する場合は、RHEL 9環境でビルドする。
現在のGLIBCバージョンは以下に示すコマンドで確認できる。
ldd --version # または rpm -q glibc
共有ライブラリの依存関係の確認
生成されたバイナリが依存している共有ライブラリを確認するには、ldd コマンドを使用する。
ldd dist/MyApplication
"not found: と表示されるライブラリがある場合、そのバイナリはターゲット環境で動作しない可能性がある。
Linux向けビルドスクリプト
#!/usr/bin/env sh
# 仮想環境のアクティベート
source venv/bin/activate
# 出力ディレクトリの作成
mkdir -p dist/linux
# PyInstallerの実行
pyinstaller --onefile \
--distpath dist/linux \
--workpath build/linux \
--add-data "config.ini:." \
--add-data "resources:resources" \
--name=MyApplication \
main.py
echo ""
echo "ビルドが完了しました。出力先: dist/linux/MyApplication"
スクリプトに実行権限を付与する。
chmod u+x build_scripts/build_linux.sh
Nuitkaを使用した高度なコンパイル
Nuitkaは、PythonコードをC言語にコンパイルしてから実行ファイルを生成するツールである。
PyInstallerと比較して、実行速度が向上し、リバースエンジニアリングへの耐性も高くなる。
Nuitkaのインストール
pip install nuitka
Windows環境では、Visual Studio Build Tools または MinGW-w64 が必要である。
Linux環境では、GCCと関連ツールが必要である。
# RHEL sudo dnf install gcc gcc-c++ # SUSE sudo zypper install gcc gcc-c++
基本的な使用方法
# CLIアプリケーションの場合 python -m nuitka --standalone --onefile your_script.py # GUIアプリケーションの場合 python -m nuitka --standalone --onefile --windows-disable-console --windows-icon-from-ico=icon.ico your_script.py
Nuitkaは初回ビルド時に時間が掛かるが、生成される実行ファイルは一般的にPyInstallerよりも高速に動作する。
トラブルシューティング
ModuleNotFoundErrorが発生する
- 原因
- PyInstallerが動的インポートや特定のライブラリのサブモジュールを検出できていない。
- 対処法
- エラーメッセージに表示されているモジュールを
--hidden-importオプションで追加する。
- エラーメッセージに表示されているモジュールを
pyinstaller --onefile --hidden-import=missing_module main.py
よく問題になるライブラリと対処例を以下に示す。
| ライブラリ | 追加が必要なモジュールの例 |
|---|---|
| pandas | pandas._libs.tslibs.timedeltas |
| PIL / Pillow | PIL._tkinter_finder |
| scikit-learn | --collect-submodules=sklearn |
ファイルが見つからないエラー
- 原因
- データファイル (設定ファイル、画像等) が実行ファイルに含まれていない、または、パスの解決が正しくない。
- 対処法
--add-dataオプションでファイルを正しく含めているか確認する。- ソースコード内で
get_resource_path()メソッドを使用してパスを解決しているかどうかを確認する。
実行ファイルのサイズが大きすぎる
対処法を以下に示す。
- 仮想環境を使用して、必要なパッケージのみをインストールした環境でビルドする。
- specファイルの excludes リストに、使用していないモジュールを追加する。
- UPX圧縮を使用する。
- もしUPXがインストールされていれば、PyInstallerは自動的に使用する。
- UPXのインストール手順を以下に示す。
# RHEL sudo dnf install upx # SUSE sudo zypper install upx
"GLIBC_X.XX not found" エラー
- 原因
- ビルド環境のGLIBCのバージョンが、実行環境より新しい。
- 対処法
- ターゲット環境と同じか、それより古いバージョンのLinuxでビルドする。
- Dockerを使用して古い環境でビルドする方法も効果的である。
- Dockerを使用したビルド方法を以下に示す。
# 例: openSUSE Leap 15.1のDockerコンテナでビルド docker run -it -v $(pwd):/app opensuse/leap:15.1 bash # コンテナ内でPythonとPyInstallerをセットアップしてビルド # ...略
手法の選択指針
| 用途 | 推奨ツール | 備考 |
|---|---|---|
| 通常の用途で手軽に実行ファイルを作成したい | PyInstaller | 豊富な情報があり、トラブルシューティングも容易 |
| 実行速度を重視する | Nuitka | ビルド環境の準備とビルド時間が増加する |
| コードの難読化を強化したい | Nuitka | C言語へのコンパイルにより難読化される |
| クロスプラットフォーム対応が必要 | PyInstaller | 各OSの環境でそれぞれビルドを行う必要がある |
クロスプラットフォーム対応が必要な場合は、各OSの環境 (実機、VM、Docker、WSL2等) でそれぞれビルドを行う必要がある。
CI/CDパイプライン (GitHub Actions等) を活用すると、複数プラットフォーム向けのビルドを自動化できる。
外部リンク